Skip to main content

pingora_core/protocols/http/
server.rs

1// Copyright 2026 Cloudflare, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! HTTP server session APIs
16
17use super::custom::server::Session as SessionCustom;
18use super::error_resp;
19use super::subrequest::server::HttpSession as SessionSubrequest;
20use super::v1::server::HttpSession as SessionV1;
21use super::v2::server::{HttpSession as SessionV2, Idle};
22use super::HttpTask;
23use crate::custom_session;
24use crate::protocols::{Digest, SocketAddr, Stream};
25use bytes::{Bytes, BytesMut};
26use http::HeaderValue;
27use http::{header::AsHeaderName, HeaderMap};
28use pingora_error::{Error, Result};
29use pingora_http::{RequestHeader, ResponseHeader};
30use std::any::Any;
31use std::time::Duration;
32
33/// A reusable HTTP/1.x stream and bytes already read for the next request.
34#[derive(Debug)]
35pub struct ReusableHttpStream {
36    stream: Stream,
37    pipelined_prefix: Option<BytesMut>,
38}
39
40impl ReusableHttpStream {
41    pub(crate) fn new(stream: Stream, pipelined_prefix: Option<BytesMut>) -> Self {
42        Self {
43            stream,
44            pipelined_prefix,
45        }
46    }
47
48    /// Split the reusable connection into its underlying stream and optional
49    /// bytes already read for the next pipelined request.
50    pub fn into_parts(self) -> (Stream, Option<BytesMut>) {
51        (self.stream, self.pipelined_prefix)
52    }
53}
54
55/// HTTP server session object for both HTTP/1.x and HTTP/2
56pub enum Session {
57    H1(SessionV1),
58    H2(SessionV2),
59    Subrequest(SessionSubrequest),
60    Custom(Box<dyn SessionCustom>),
61}
62
63impl Session {
64    /// Create a new [`Session`] from an established connection for HTTP/1.x
65    pub fn new_http1(stream: Stream) -> Self {
66        Self::H1(SessionV1::new(stream))
67    }
68
69    /// Create a new [`Session`] from an established HTTP/2 stream
70    pub fn new_http2(session: SessionV2) -> Self {
71        Self::H2(session)
72    }
73
74    /// Create a new [`Session`] from a subrequest session
75    pub fn new_subrequest(session: SessionSubrequest) -> Self {
76        Self::Subrequest(session)
77    }
78
79    /// Create a new [`Session`] from a custom session
80    pub fn new_custom(session: Box<dyn SessionCustom>) -> Self {
81        Self::Custom(session)
82    }
83
84    /// Whether the session is HTTP/2. If not it is HTTP/1.x
85    pub fn is_http2(&self) -> bool {
86        matches!(self, Self::H2(_))
87    }
88
89    /// Whether the session is for a subrequest.
90    pub fn is_subrequest(&self) -> bool {
91        matches!(self, Self::Subrequest(_))
92    }
93
94    /// Whether the session is Custom
95    pub fn is_custom(&self) -> bool {
96        matches!(self, Self::Custom(_))
97    }
98
99    /// Return a stable, human-readable label for this downstream session type.
100    pub fn session_type(&self) -> &'static str {
101        match self {
102            Self::H1(_) => "h1",
103            Self::H2(_) => "h2",
104            Self::Subrequest(_) => "subrequest",
105            Self::Custom(_) => "custom",
106        }
107    }
108
109    /// Read the request header. This method is required to be called first before doing anything
110    /// else with the session.
111    /// - `Ok(true)`: successful
112    /// - `Ok(false)`: client exit without sending any bytes. This is normal on reused connection.
113    ///   In this case the user should give up this session.
114    pub async fn read_request(&mut self) -> Result<bool> {
115        match self {
116            Self::H1(s) => {
117                let read = s.read_request().await?;
118                Ok(read.is_some())
119            }
120            // This call will always return `Ok(true)` for Http2 because the request is already read
121            Self::H2(_) => Ok(true),
122            Self::Subrequest(s) => {
123                let read = s.read_request().await?;
124                Ok(read.is_some())
125            }
126            Self::Custom(_) => Ok(true),
127        }
128    }
129
130    /// Return the request header it just read.
131    /// # Panic
132    /// This function will panic if [`Self::read_request()`] is not called.
133    pub fn req_header(&self) -> &RequestHeader {
134        match self {
135            Self::H1(s) => s.req_header(),
136            Self::H2(s) => s.req_header(),
137            Self::Subrequest(s) => s.req_header(),
138            Self::Custom(s) => s.req_header(),
139        }
140    }
141
142    /// Return a mutable reference to request header it just read.
143    /// # Panic
144    /// This function will panic if [`Self::read_request()`] is not called.
145    pub fn req_header_mut(&mut self) -> &mut RequestHeader {
146        match self {
147            Self::H1(s) => s.req_header_mut(),
148            Self::H2(s) => s.req_header_mut(),
149            Self::Subrequest(s) => s.req_header_mut(),
150            Self::Custom(s) => s.req_header_mut(),
151        }
152    }
153
154    /// Return the header by name. None if the header doesn't exist.
155    ///
156    /// In case there are multiple headers under the same name, the first one will be returned. To
157    /// get all the headers: use `self.req_header().headers.get_all()`.
158    pub fn get_header<K: AsHeaderName>(&self, key: K) -> Option<&HeaderValue> {
159        self.req_header().headers.get(key)
160    }
161
162    /// Get the header value in its raw format.
163    /// If the header doesn't exist, return an empty slice.
164    pub fn get_header_bytes<K: AsHeaderName>(&self, key: K) -> &[u8] {
165        self.get_header(key).map_or(b"", |v| v.as_bytes())
166    }
167
168    /// Read the request body. Ok(None) if no (more) body to read
169    pub async fn read_request_body(&mut self) -> Result<Option<Bytes>> {
170        match self {
171            Self::H1(s) => s.read_body_bytes().await,
172            Self::H2(s) => s.read_body_bytes().await,
173            Self::Subrequest(s) => s.read_body_bytes().await,
174            Self::Custom(s) => s.read_body_bytes().await,
175        }
176    }
177
178    /// Discard the request body by reading it until completion.
179    ///
180    /// This is useful for making streams reusable (in particular for HTTP/1.1) after returning an
181    /// error before the whole body has been read.
182    pub async fn drain_request_body(&mut self) -> Result<()> {
183        match self {
184            Self::H1(s) => s.drain_request_body().await,
185            Self::H2(s) => s.drain_request_body().await,
186            Self::Subrequest(s) => s.drain_request_body().await,
187            Self::Custom(s) => s.drain_request_body().await,
188        }
189    }
190
191    /// Write the response header to client
192    /// Informational headers (status code 100-199, excluding 101) can be written multiple times the final
193    /// response header (status code 200+ or 101) is written.
194    pub async fn write_response_header(&mut self, resp: Box<ResponseHeader>) -> Result<()> {
195        match self {
196            Self::H1(s) => {
197                s.write_response_header(resp).await?;
198                Ok(())
199            }
200            Self::H2(s) => s.write_response_header(resp, false),
201            Self::Subrequest(s) => {
202                s.write_response_header(resp).await?;
203                Ok(())
204            }
205            Self::Custom(s) => s.write_response_header(resp, false).await,
206        }
207    }
208
209    /// Similar to `write_response_header()`, this fn will clone the `resp` internally
210    pub async fn write_response_header_ref(&mut self, resp: &ResponseHeader) -> Result<()> {
211        match self {
212            Self::H1(s) => {
213                s.write_response_header_ref(resp).await?;
214                Ok(())
215            }
216            Self::H2(s) => s.write_response_header_ref(resp, false),
217            Self::Subrequest(s) => {
218                s.write_response_header_ref(resp).await?;
219                Ok(())
220            }
221            Self::Custom(s) => s.write_response_header_ref(resp, false).await,
222        }
223    }
224
225    /// Write the response body to client
226    pub async fn write_response_body(&mut self, data: Bytes, end: bool) -> Result<()> {
227        if data.is_empty() && !end {
228            // writing 0 byte to a chunked encoding h1 would finish the stream
229            // writing 0 bytes to h2 is noop
230            // we don't want to actually write in either cases
231            return Ok(());
232        }
233        match self {
234            Self::H1(s) => {
235                if !data.is_empty() {
236                    s.write_body(&data).await?;
237                }
238                if end {
239                    s.finish_body().await?;
240                }
241                Ok(())
242            }
243            Self::H2(s) => s.write_body(data, end).await,
244            Self::Subrequest(s) => {
245                s.write_body(data).await?;
246                Ok(())
247            }
248            Self::Custom(s) => s.write_body(data, end).await,
249        }
250    }
251
252    /// Write the response trailers to client
253    pub async fn write_response_trailers(&mut self, trailers: HeaderMap) -> Result<()> {
254        match self {
255            Self::H1(_) => Ok(()), // TODO: support trailers for h1
256            Self::H2(s) => s.write_trailers(trailers),
257            Self::Subrequest(s) => s.write_trailers(Some(Box::new(trailers))).await,
258            Self::Custom(s) => s.write_trailers(trailers).await,
259        }
260    }
261
262    /// Finish the life of this request and return a reusable stream, if any.
263    ///
264    /// For H1, if connection reuse is supported, a reusable stream will be returned,
265    /// otherwise None.
266    /// For H2, always return None because H2 stream is not reusable.
267    /// For subrequests, there is no true underlying stream to return.
268    pub async fn finish(self) -> Result<Option<ReusableHttpStream>> {
269        match self {
270            Self::H1(mut s) => {
271                // need to flush body due to buffering
272                s.finish_body().await?;
273                s.reuse().await
274            }
275            Self::H2(mut s) => {
276                s.finish()?;
277                Ok(None)
278            }
279            Self::Subrequest(mut s) => {
280                s.finish().await?;
281                Ok(None)
282            }
283            Self::Custom(mut s) => {
284                s.finish().await?;
285                Ok(None)
286            }
287        }
288    }
289
290    /// Callback for cleanup logic on downstream specifically when we fail to proxy the session
291    /// other than cleanup via finish().
292    ///
293    /// If caching the downstream failure may be independent of (and precede) an upstream error in
294    /// which case this function may be called more than once.
295    pub fn on_proxy_failure(&mut self, e: Box<Error>) {
296        match self {
297            Self::H1(_) | Self::H2(_) | Self::Custom(_) => {
298                // all cleanup logic handled in finish(),
299                // stream and resources dropped when session dropped
300            }
301            Self::Subrequest(ref mut s) => s.on_proxy_failure(e),
302        }
303    }
304
305    pub async fn response_duplex_vec(&mut self, tasks: Vec<HttpTask>) -> Result<bool> {
306        match self {
307            Self::H1(s) => s.response_duplex_vec(tasks).await,
308            Self::H2(s) => s.response_duplex_vec(tasks).await,
309            Self::Subrequest(s) => s.response_duplex_vec(tasks).await,
310            Self::Custom(s) => s.response_duplex_vec(tasks).await,
311        }
312    }
313
314    /// Set connection reuse. `duration` defines how long the connection is kept open for the next
315    /// request to reuse. Noop for h2 and subrequest
316    pub fn set_keepalive(&mut self, duration: Option<u64>) {
317        match self {
318            Self::H1(s) => s.set_server_keepalive(duration),
319            Self::H2(_) => {}
320            Self::Subrequest(_) => {}
321            Self::Custom(_) => {}
322        }
323    }
324
325    /// Get the keepalive timeout. None if keepalive is disabled. Not applicable for h2 or
326    /// subrequest
327    pub fn get_keepalive(&self) -> Option<u64> {
328        match self {
329            Self::H1(s) => s.get_keepalive_timeout(),
330            Self::H2(_) => None,
331            Self::Subrequest(_) => None,
332            Self::Custom(_) => None,
333        }
334    }
335
336    /// Set the number of times the upstream connection connection for this
337    /// session can be reused via keepalive. Noop for h2 and subrequest
338    pub fn set_keepalive_reuses_remaining(&mut self, reuses: Option<u32>) {
339        if let Self::H1(s) = self {
340            s.set_keepalive_reuses_remaining(reuses);
341        }
342    }
343
344    /// Get the number of times the upstream connection connection for this
345    /// session can be reused via keepalive. Not applicable for h2 or
346    /// subrequest
347    pub fn get_keepalive_reuses_remaining(&self) -> Option<u32> {
348        if let Self::H1(s) = self {
349            s.get_keepalive_reuses_remaining()
350        } else {
351            None
352        }
353    }
354
355    /// Set user-defined context to carry across requests on the same keepalive connection.
356    ///
357    /// Only applicable for HTTP/1.x connections; noop for h2, subrequest, and custom sessions.
358    pub fn set_connection_user_context(&mut self, ctx: Option<Box<dyn Any + Send + Sync>>) {
359        if let Self::H1(s) = self {
360            s.set_connection_user_context(ctx);
361        }
362    }
363
364    /// Take the user-defined context from the previous request on this keepalive connection.
365    ///
366    /// Returns `None` for h2, subrequest, and custom sessions, or if no context was persisted.
367    pub fn take_connection_user_context(&mut self) -> Option<Box<dyn Any + Send + Sync>> {
368        if let Self::H1(s) = self {
369            s.take_connection_user_context()
370        } else {
371            None
372        }
373    }
374
375    /// Sets the downstream read timeout. This will trigger if we're unable
376    /// to read from the stream after `timeout`.
377    ///
378    /// This is a noop for h2.
379    pub fn set_read_timeout(&mut self, timeout: Option<Duration>) {
380        match self {
381            Self::H1(s) => s.set_read_timeout(timeout),
382            Self::H2(_) => {}
383            Self::Subrequest(s) => s.set_read_timeout(timeout),
384            Self::Custom(c) => c.set_read_timeout(timeout),
385        }
386    }
387
388    /// Gets the downstream read timeout if set.
389    pub fn get_read_timeout(&self) -> Option<Duration> {
390        match self {
391            Self::H1(s) => s.get_read_timeout(),
392            Self::H2(_) => None,
393            Self::Subrequest(s) => s.get_read_timeout(),
394            Self::Custom(s) => s.get_read_timeout(),
395        }
396    }
397
398    /// Sets the downstream write timeout. This will trigger if we're unable
399    /// to write to the stream after `timeout`. If a `min_send_rate` is
400    /// configured then the `min_send_rate` calculated timeout has higher priority.
401    pub fn set_write_timeout(&mut self, timeout: Option<Duration>) {
402        match self {
403            Self::H1(s) => s.set_write_timeout(timeout),
404            Self::H2(s) => s.set_write_timeout(timeout),
405            Self::Subrequest(s) => s.set_write_timeout(timeout),
406            Self::Custom(c) => c.set_write_timeout(timeout),
407        }
408    }
409
410    /// Gets the downstream write timeout if set.
411    pub fn get_write_timeout(&self) -> Option<Duration> {
412        match self {
413            Self::H1(s) => s.get_write_timeout(),
414            Self::H2(s) => s.get_write_timeout(),
415            Self::Subrequest(s) => s.get_write_timeout(),
416            Self::Custom(s) => s.get_write_timeout(),
417        }
418    }
419
420    /// Sets the total drain timeout, which will be applied while discarding the
421    /// request body using `drain_request_body`.
422    ///
423    /// For HTTP/1.1, reusing a session requires ensuring that the request body
424    /// is consumed. If the timeout is exceeded, the caller should give up on
425    /// trying to reuse the session.
426    pub fn set_total_drain_timeout(&mut self, timeout: Option<Duration>) {
427        match self {
428            Self::H1(s) => s.set_total_drain_timeout(timeout),
429            Self::H2(s) => s.set_total_drain_timeout(timeout),
430            Self::Subrequest(s) => s.set_total_drain_timeout(timeout),
431            Self::Custom(c) => c.set_total_drain_timeout(timeout),
432        }
433    }
434
435    /// Gets the total drain timeout if set.
436    pub fn get_total_drain_timeout(&self) -> Option<Duration> {
437        match self {
438            Self::H1(s) => s.get_total_drain_timeout(),
439            Self::H2(s) => s.get_total_drain_timeout(),
440            Self::Subrequest(s) => s.get_total_drain_timeout(),
441            Self::Custom(s) => s.get_total_drain_timeout(),
442        }
443    }
444
445    /// Sets the minimum downstream send rate in bytes per second. This
446    /// is used to calculate a write timeout in seconds based on the size
447    /// of the buffer being written. If a `min_send_rate` is configured it
448    /// has higher priority over a set `write_timeout`. The minimum send
449    /// rate must be greater than zero.
450    ///
451    /// Calculated write timeout is guaranteed to be at least 1s if `min_send_rate`
452    /// is greater than zero, a send rate of zero is equivalent to disabling.
453    ///
454    /// This is a noop for h2.
455    pub fn set_min_send_rate(&mut self, rate: Option<usize>) {
456        match self {
457            Self::H1(s) => s.set_min_send_rate(rate),
458            Self::H2(_) => {}
459            Self::Subrequest(_) => {}
460            Self::Custom(_) => {}
461        }
462    }
463
464    /// Sets whether we ignore writing informational responses downstream.
465    ///
466    /// For HTTP/1.1 this is a noop if the response is Upgrade or Continue and
467    /// Expect: 100-continue was set on the request.
468    ///
469    /// This is a noop for h2 because informational responses are always ignored.
470    /// Subrequests will always proxy the info response and let the true downstream
471    /// decide to ignore or not.
472    pub fn set_ignore_info_resp(&mut self, ignore: bool) {
473        match self {
474            Self::H1(s) => s.set_ignore_info_resp(ignore),
475            Self::H2(_) => {} // always ignored
476            Self::Subrequest(_) => {}
477            Self::Custom(_) => {} // always ignored
478        }
479    }
480
481    /// Sets whether keepalive should be disabled if response is written prior to
482    /// downstream body finishing.
483    ///
484    /// This is a noop for h2.
485    pub fn set_close_on_response_before_downstream_finish(&mut self, close: bool) {
486        match self {
487            Self::H1(s) => s.set_close_on_response_before_downstream_finish(close),
488            Self::H2(_) => {}         // always ignored
489            Self::Subrequest(_) => {} // always ignored
490            Self::Custom(_) => {}     // always ignored
491        }
492    }
493
494    /// Controls behaviour when the client closes the connection after the request body.
495    ///
496    /// When **enabled** (default), a client close is returned as a `ConnectionClosed`
497    /// error so the proxy aborts immediately. When **disabled**, `read_body_or_idle`
498    /// stays pending so the proxy can finish delivering the upstream response.
499    ///
500    /// Only meaningful for H1 (TCP). Noop for H2/subrequest/custom.
501    pub fn set_abort_on_close(&mut self, abort: bool) {
502        match self {
503            Self::H1(s) => s.set_abort_on_close(abort),
504            Self::H2(_) => {}
505            Self::Subrequest(_) => {}
506            Self::Custom(_) => {}
507        }
508    }
509
510    /// Return a digest of the request including the method, path and Host header
511    // TODO: make this use a `Formatter`
512    pub fn request_summary(&self) -> String {
513        match self {
514            Self::H1(s) => s.request_summary(),
515            Self::H2(s) => s.request_summary(),
516            Self::Subrequest(s) => s.request_summary(),
517            Self::Custom(s) => s.request_summary(),
518        }
519    }
520
521    /// Return the written response header. `None` if it is not written yet.
522    /// Only the final (status code >= 200 or 101) response header will be returned
523    pub fn response_written(&self) -> Option<&ResponseHeader> {
524        match self {
525            Self::H1(s) => s.response_written(),
526            Self::H2(s) => s.response_written(),
527            Self::Subrequest(s) => s.response_written(),
528            Self::Custom(s) => s.response_written(),
529        }
530    }
531
532    /// Give up the http session abruptly.
533    ///
534    /// This is a failure path: the response is abandoned mid-message, so each
535    /// protocol signals it in whatever way lets the peer tell this apart from a
536    /// response that was completed.
537    /// For H1 this will close the underlying connection
538    /// For H2 this will send RESET frame to end this stream without impacting the connection
539    /// For subrequests, this will drop task senders and receivers.
540    pub async fn shutdown(&mut self) {
541        match self {
542            Self::H1(s) => s.shutdown().await,
543            Self::H2(s) => s.shutdown(),
544            Self::Subrequest(s) => s.shutdown(),
545            Self::Custom(s) => s.abandon("shutdown").await,
546        }
547    }
548
549    /// Give up the H2 stream with a custom reason.
550    ///
551    /// For H2, this sends a `RST_STREAM` frame with the specified reason.
552    /// For H1, subrequests, and custom sessions, this is a no-op since they don't support
553    /// stream reset reasons.
554    ///
555    /// See [`super::v2::server::HttpSession::shutdown_with_reason`] for available reasons.
556    pub fn shutdown_with_reason(&mut self, reason: h2::Reason) {
557        if let Self::H2(s) = self {
558            s.shutdown_with_reason(reason);
559        }
560    }
561
562    pub fn to_h1_raw(&self) -> Bytes {
563        match self {
564            Self::H1(s) => s.get_headers_raw_bytes(),
565            Self::H2(s) => s.pseudo_raw_h1_request_header(),
566            Self::Subrequest(s) => s.get_headers_raw_bytes(),
567            Self::Custom(c) => c.pseudo_raw_h1_request_header(),
568        }
569    }
570
571    /// Whether the whole request body is sent
572    pub fn is_body_done(&mut self) -> bool {
573        match self {
574            Self::H1(s) => s.is_body_done(),
575            Self::H2(s) => s.is_body_done(),
576            Self::Subrequest(s) => s.is_body_done(),
577            Self::Custom(s) => s.is_body_done(),
578        }
579    }
580
581    /// Notify the client that the entire body is sent
582    /// for H1 chunked encoding, this will end the last empty chunk
583    /// for H1 content-length, this has no effect.
584    /// for H2, this will send an empty DATA frame with END_STREAM flag
585    /// for subrequest, this will send a Done http task
586    pub async fn finish_body(&mut self) -> Result<()> {
587        match self {
588            Self::H1(s) => s.finish_body().await.map(|_| ()),
589            Self::H2(s) => s.finish(),
590            Self::Subrequest(s) => s.finish().await.map(|_| ()),
591            Self::Custom(s) => s.finish().await,
592        }
593    }
594
595    pub fn generate_error(error: u16) -> ResponseHeader {
596        match error {
597            /* common error responses are pre-generated */
598            502 => error_resp::HTTP_502_RESPONSE.clone(),
599            400 => error_resp::HTTP_400_RESPONSE.clone(),
600            _ => error_resp::gen_error_response(error),
601        }
602    }
603
604    /// Send error response to client using a pre-generated error message.
605    pub async fn respond_error(&mut self, error: u16) -> Result<()> {
606        self.respond_error_with_body(error, Bytes::default()).await
607    }
608
609    /// Send error response to client using a pre-generated error message and custom body.
610    pub async fn respond_error_with_body(&mut self, error: u16, body: Bytes) -> Result<()> {
611        let mut resp = Self::generate_error(error);
612        if !body.is_empty() {
613            // error responses have a default content-length of zero
614            resp.set_content_length(body.len())?
615        }
616        self.write_error_response(resp, body).await
617    }
618
619    /// Send an error response to a client with a response header and body.
620    pub async fn write_error_response(&mut self, resp: ResponseHeader, body: Bytes) -> Result<()> {
621        // TODO: we shouldn't be closing downstream connections on internally generated errors
622        // and possibly other upstream connect() errors (connection refused, timeout, etc)
623        //
624        // This change is only here because we DO NOT re-use downstream connections
625        // today on these errors and we should signal to the client that pingora is dropping it
626        // rather than a misleading the client with 'keep-alive'
627        self.set_keepalive(None);
628
629        // If a response was already written and it's not informational 1xx, return.
630        // The only exception is an informational 101 Switching Protocols, which is treated
631        // as final response https://www.rfc-editor.org/rfc/rfc9110#section-15.2.2.
632        if let Some(resp_written) = self.response_written().as_ref() {
633            if !resp_written.status.is_informational() || resp_written.status == 101 {
634                return Ok(());
635            }
636        }
637
638        self.write_response_header(Box::new(resp)).await?;
639
640        if !body.is_empty() {
641            self.write_response_body(body, true).await?;
642        } else {
643            self.finish_body().await?;
644        }
645
646        custom_session!(self.finish_custom().await?);
647
648        Ok(())
649    }
650
651    /// Whether there is no request body
652    pub fn is_body_empty(&mut self) -> bool {
653        match self {
654            Self::H1(s) => s.is_body_empty(),
655            Self::H2(s) => s.is_body_empty(),
656            Self::Subrequest(s) => s.is_body_empty(),
657            Self::Custom(s) => s.is_body_empty(),
658        }
659    }
660
661    pub fn retry_buffer_truncated(&self) -> bool {
662        match self {
663            Self::H1(s) => s.retry_buffer_truncated(),
664            Self::H2(s) => s.retry_buffer_truncated(),
665            Self::Subrequest(s) => s.retry_buffer_truncated(),
666            Self::Custom(s) => s.retry_buffer_truncated(),
667        }
668    }
669
670    pub fn enable_retry_buffering(&mut self) {
671        match self {
672            Self::H1(s) => s.enable_retry_buffering(),
673            Self::H2(s) => s.enable_retry_buffering(),
674            Self::Subrequest(s) => s.enable_retry_buffering(),
675            Self::Custom(s) => s.enable_retry_buffering(),
676        }
677    }
678
679    pub fn get_retry_buffer(&self) -> Option<Bytes> {
680        match self {
681            Self::H1(s) => s.get_retry_buffer(),
682            Self::H2(s) => s.get_retry_buffer(),
683            Self::Subrequest(s) => s.get_retry_buffer(),
684            Self::Custom(s) => s.get_retry_buffer(),
685        }
686    }
687
688    /// Read body (same as `read_request_body()`) or pending forever until downstream
689    /// terminates the session.
690    pub async fn read_body_or_idle(&mut self, no_body_expected: bool) -> Result<Option<Bytes>> {
691        match self {
692            Self::H1(s) => s.read_body_or_idle(no_body_expected).await,
693            Self::H2(s) => s.read_body_or_idle(no_body_expected).await,
694            Self::Subrequest(s) => s.read_body_or_idle(no_body_expected).await,
695            Self::Custom(s) => s.read_body_or_idle(no_body_expected).await,
696        }
697    }
698
699    /// Return an [`Idle`] future that waits for this H2 stream to close without
700    /// reading any body data.
701    ///
702    /// For HTTP/2 this resolves when the client resets the stream (`RST_STREAM`),
703    /// cleanly closes the stream, or the stream errors. Other protocols have no
704    /// out-of-band close signal, so this returns `None` for them.
705    pub fn watch_h2_stream_close(&mut self) -> Option<Idle<'_>> {
706        match self {
707            Self::H2(s) => Some(s.idle()),
708            _ => None,
709        }
710    }
711
712    pub fn as_http1(&self) -> Option<&SessionV1> {
713        match self {
714            Self::H1(s) => Some(s),
715            Self::H2(_) => None,
716            Self::Subrequest(_) => None,
717            Self::Custom(_) => None,
718        }
719    }
720
721    pub fn as_http2(&self) -> Option<&SessionV2> {
722        match self {
723            Self::H1(_) => None,
724            Self::H2(s) => Some(s),
725            Self::Subrequest(_) => None,
726            Self::Custom(_) => None,
727        }
728    }
729
730    pub fn as_subrequest(&self) -> Option<&SessionSubrequest> {
731        match self {
732            Self::H1(_) => None,
733            Self::H2(_) => None,
734            Self::Subrequest(s) => Some(s),
735            Self::Custom(_) => None,
736        }
737    }
738
739    pub fn as_subrequest_mut(&mut self) -> Option<&mut SessionSubrequest> {
740        match self {
741            Self::H1(_) => None,
742            Self::H2(_) => None,
743            Self::Subrequest(s) => Some(s),
744            Self::Custom(_) => None,
745        }
746    }
747
748    pub fn as_custom(&self) -> Option<&dyn SessionCustom> {
749        match self {
750            Self::H1(_) => None,
751            Self::H2(_) => None,
752            Self::Subrequest(_) => None,
753            Self::Custom(c) => Some(c.as_ref()),
754        }
755    }
756
757    pub fn as_custom_mut(&mut self) -> Option<&mut Box<dyn SessionCustom>> {
758        match self {
759            Self::H1(_) => None,
760            Self::H2(_) => None,
761            Self::Subrequest(_) => None,
762            Self::Custom(c) => Some(c),
763        }
764    }
765
766    /// Write a 100 Continue response to the client.
767    pub async fn write_continue_response(&mut self) -> Result<()> {
768        match self {
769            Self::H1(s) => s.write_continue_response().await,
770            Self::H2(s) => s.write_response_header(
771                Box::new(ResponseHeader::build(100, Some(0)).unwrap()),
772                false,
773            ),
774            Self::Subrequest(s) => s.write_continue_response().await,
775            // TODO(slava): is there any write_continue_response calls?
776            Self::Custom(s) => {
777                s.write_response_header(
778                    Box::new(ResponseHeader::build(100, Some(0)).unwrap()),
779                    false,
780                )
781                .await
782            }
783        }
784    }
785
786    /// Whether this request is for upgrade (e.g., websocket).
787    pub fn is_upgrade_req(&self) -> bool {
788        match self {
789            Self::H1(s) => s.is_upgrade_req(),
790            Self::H2(_) => false,
791            Self::Subrequest(s) => s.is_upgrade_req(),
792            Self::Custom(s) => s.is_upgrade_req(),
793        }
794    }
795
796    /// Return whether this response completes an upgrade handshake.
797    ///
798    /// Returns `Some(true)` when an upgrade request gets an upgrade response,
799    /// `Some(false)` when an upgrade request gets a non-upgrade response, and
800    /// `None` when this request is not an upgrade.
801    pub fn is_upgrade(&self, header: &ResponseHeader) -> Option<bool> {
802        match self {
803            Self::H1(s) => s.is_upgrade(header),
804            Self::H2(_) => None,
805            Self::Subrequest(s) => s.is_upgrade(header),
806            Self::Custom(s) => {
807                if s.is_upgrade_req() {
808                    Some(super::v1::common::is_upgrade_resp(header))
809                } else {
810                    None
811                }
812            }
813        }
814    }
815
816    /// Whether this session was fully upgraded (completed Upgrade handshake).
817    pub fn was_upgraded(&self) -> bool {
818        match self {
819            Self::H1(s) => s.was_upgraded(),
820            Self::H2(_) => false,
821            Self::Subrequest(s) => s.was_upgraded(),
822            Self::Custom(s) => s.was_upgraded(),
823        }
824    }
825
826    /// Return how many response body bytes (application, not wire) already sent downstream
827    pub fn body_bytes_sent(&self) -> usize {
828        match self {
829            Self::H1(s) => s.body_bytes_sent(),
830            Self::H2(s) => s.body_bytes_sent(),
831            Self::Subrequest(s) => s.body_bytes_sent(),
832            Self::Custom(s) => s.body_bytes_sent(),
833        }
834    }
835
836    /// Return how many request body bytes (application, not wire) already read from downstream
837    pub fn body_bytes_read(&self) -> usize {
838        match self {
839            Self::H1(s) => s.body_bytes_read(),
840            Self::H2(s) => s.body_bytes_read(),
841            Self::Subrequest(s) => s.body_bytes_read(),
842            Self::Custom(s) => s.body_bytes_read(),
843        }
844    }
845
846    /// Return the [Digest] for the connection.
847    pub fn digest(&self) -> Option<&Digest> {
848        match self {
849            Self::H1(s) => Some(s.digest()),
850            Self::H2(s) => s.digest(),
851            Self::Subrequest(s) => s.digest(),
852            Self::Custom(s) => s.digest(),
853        }
854    }
855
856    /// Return a mutable [Digest] reference for the connection.
857    ///
858    /// Will return `None` if multiple H2 streams are open.
859    pub fn digest_mut(&mut self) -> Option<&mut Digest> {
860        match self {
861            Self::H1(s) => Some(s.digest_mut()),
862            Self::H2(s) => s.digest_mut(),
863            Self::Subrequest(s) => s.digest_mut(),
864            Self::Custom(s) => s.digest_mut(),
865        }
866    }
867
868    /// Return the client (peer) address of the connection.
869    pub fn client_addr(&self) -> Option<&SocketAddr> {
870        match self {
871            Self::H1(s) => s.client_addr(),
872            Self::H2(s) => s.client_addr(),
873            Self::Subrequest(s) => s.client_addr(),
874            Self::Custom(s) => s.client_addr(),
875        }
876    }
877
878    /// Return the server (local) address of the connection.
879    pub fn server_addr(&self) -> Option<&SocketAddr> {
880        match self {
881            Self::H1(s) => s.server_addr(),
882            Self::H2(s) => s.server_addr(),
883            Self::Subrequest(s) => s.server_addr(),
884            Self::Custom(s) => s.server_addr(),
885        }
886    }
887
888    /// Get the reference of the [Stream] that this HTTP/1 session is operating upon.
889    /// None if the HTTP session is over H2, or a subrequest
890    pub fn stream(&self) -> Option<&Stream> {
891        match self {
892            Self::H1(s) => Some(s.stream()),
893            Self::H2(_) => None,
894            Self::Subrequest(_) => None,
895            Self::Custom(_) => None,
896        }
897    }
898
899    /// Check if this session supports the cancel-safe proxy task API.
900    ///
901    /// Currently supported by HTTP/1.x, Subrequest, and opted-in Custom
902    /// server sessions; toggled per-session via
903    /// [`set_proxy_tasks_enabled`](Self::set_proxy_tasks_enabled).
904    pub fn supports_proxy_task_api(&self) -> bool {
905        match self {
906            Self::H1(s) => s.proxy_tasks_enabled(),
907            Self::Subrequest(s) => s.proxy_tasks_enabled(),
908            Self::Custom(s) => s.proxy_tasks_enabled(),
909            Self::H2(_) => false,
910        }
911    }
912
913    /// Enable or disable the cancel-safe proxy task API for this session.
914    pub fn set_proxy_tasks_enabled(&mut self, enabled: bool) {
915        match self {
916            Self::H1(s) => s.set_proxy_tasks_enabled(enabled),
917            Self::Subrequest(s) => s.set_proxy_tasks_enabled(enabled),
918            Self::Custom(s) => s.set_proxy_tasks_enabled(enabled),
919            Self::H2(_) => {}
920        }
921    }
922
923    /// Whether HTTP/1.1 request pipelining is enabled for this session.
924    ///
925    /// Always false for H2 / Subrequest / Custom (pipelining is an H/1.1-only
926    /// concept). For H1, see
927    /// [`HttpSession::set_pipelining_enabled`](crate::protocols::http::v1::server::HttpSession::set_pipelining_enabled).
928    pub fn pipelining_enabled(&self) -> bool {
929        match self {
930            Self::H1(s) => s.pipelining_enabled(),
931            _ => false,
932        }
933    }
934
935    /// Enable or disable HTTP/1.1 request pipelining on this session.
936    ///
937    /// No-op for H2 / Subrequest / Custom. See
938    /// [`HttpSession::set_pipelining_enabled`](crate::protocols::http::v1::server::HttpSession::set_pipelining_enabled)
939    /// for semantics.
940    pub fn set_pipelining_enabled(&mut self, enabled: bool) {
941        if let Self::H1(s) = self {
942            s.set_pipelining_enabled(enabled);
943        }
944    }
945
946    /// Set pipelined bytes to be parsed as the start of this session's request.
947    ///
948    /// No-op for non-H1 sessions. See
949    /// [`HttpSession::set_pipelined_prefix`](crate::protocols::http::v1::server::HttpSession::set_pipelined_prefix)
950    /// for the lifecycle.
951    pub fn set_pipelined_prefix(&mut self, prefix: BytesMut) {
952        if let Self::H1(s) = self {
953            s.set_pipelined_prefix(prefix);
954        }
955    }
956
957    /// Queue a downstream proxy task for cancel-safe writing.
958    ///
959    /// # Panics
960    /// Panics if called on a session that doesn't support the proxy task API.
961    /// Check [`supports_proxy_task_api`](Self::supports_proxy_task_api) first,
962    /// or use `write_response_header()` / `write_response_body()` for other
963    /// session types.
964    #[track_caller]
965    pub fn send_downstream_proxy_task(&mut self, task: HttpTask) {
966        match self {
967            Self::H1(s) => s.send_proxy_task(task),
968            Self::H2(_) => panic!("H2 proxy task API not yet implemented"),
969            Self::Subrequest(s) => s.send_proxy_task(task),
970            Self::Custom(s) => s.send_proxy_task(task),
971        }
972    }
973
974    /// Check if there are pending downstream proxy tasks queued for writing.
975    ///
976    /// Returns false for sessions that don't support the proxy task API.
977    pub fn has_pending_downstream_proxy_tasks(&self) -> bool {
978        match self {
979            Self::H1(s) => s.has_pending_proxy_tasks(),
980            Self::H2(_) => false, // TODO: implement for H2
981            Self::Subrequest(s) => s.has_pending_proxy_tasks(),
982            Self::Custom(s) => s.has_pending_proxy_tasks(),
983        }
984    }
985
986    /// Write all queued downstream proxy tasks in a cancel-safe manner.
987    /// Returns `Ok(true)` if this was the end of the response stream.
988    ///
989    /// # Panics
990    /// Panics if called on a session that doesn't support the proxy task API.
991    /// Check [`supports_proxy_task_api`](Self::supports_proxy_task_api) first,
992    /// or use `write_response_header()` / `write_response_body()` for other
993    /// session types.
994    pub async fn write_downstream_proxy_tasks(&mut self) -> Result<bool> {
995        match self {
996            Self::H1(s) => s.write_proxy_tasks().await,
997            Self::H2(_) => panic!("H2 proxy task API not yet implemented"),
998            Self::Subrequest(s) => s.write_proxy_tasks().await,
999            Self::Custom(s) => s.write_proxy_tasks().await,
1000        }
1001    }
1002}
1003
1004#[cfg(test)]
1005mod tests {
1006    use super::*;
1007    use crate::protocols::http::custom::CustomMessageWrite;
1008    use async_trait::async_trait;
1009    use futures::Stream;
1010    use std::panic::{catch_unwind, AssertUnwindSafe};
1011    use std::sync::{Arc, Mutex};
1012
1013    #[tokio::test]
1014    async fn custom_proxy_task_defaults_are_opted_out_and_fail_loudly() {
1015        let mut session = Session::new_custom(Box::new(()));
1016
1017        assert!(!session.supports_proxy_task_api());
1018        session.set_proxy_tasks_enabled(true);
1019        assert!(!session.supports_proxy_task_api());
1020        assert!(!session.has_pending_downstream_proxy_tasks());
1021
1022        assert!(catch_unwind(AssertUnwindSafe(|| {
1023            session.send_downstream_proxy_task(HttpTask::Done);
1024        }))
1025        .is_err());
1026
1027        let join = tokio::spawn(async move { session.write_downstream_proxy_tasks().await });
1028        assert!(join.await.unwrap_err().is_panic());
1029    }
1030
1031    #[tokio::test]
1032    async fn custom_proxy_task_methods_delegate_to_the_custom_session() {
1033        let mut session = Session::new_custom(Box::new(ProxyTaskCustom::new()));
1034
1035        assert!(!session.supports_proxy_task_api());
1036        session.set_proxy_tasks_enabled(true);
1037        assert!(session.supports_proxy_task_api());
1038
1039        session.send_downstream_proxy_task(HttpTask::Done);
1040        assert!(session.has_pending_downstream_proxy_tasks());
1041        assert!(session.write_downstream_proxy_tasks().await.unwrap());
1042        assert!(!session.has_pending_downstream_proxy_tasks());
1043    }
1044
1045    /// `Session::shutdown` abandons a response mid-message, so it must take the
1046    /// entry point that lets a custom protocol convey exactly that. Routing it to
1047    /// the bare `shutdown` instead leaves the protocol with no way to distinguish
1048    /// an abandoned response from a completed one, which a peer can then read as
1049    /// success.
1050    #[tokio::test]
1051    async fn custom_session_shutdown_signals_an_incomplete_message() {
1052        let shutdown_calls = Arc::new(Mutex::new(Vec::new()));
1053        let mut session = Session::new_custom(Box::new(ProxyTaskCustom::with_shutdown_calls(
1054            shutdown_calls.clone(),
1055        )));
1056
1057        session.shutdown().await;
1058
1059        assert_eq!(*shutdown_calls.lock().unwrap(), ["abandon(shutdown)"]);
1060    }
1061
1062    struct ProxyTaskCustom {
1063        header: RequestHeader,
1064        enabled: bool,
1065        tasks: Vec<HttpTask>,
1066        shutdown_calls: Arc<Mutex<Vec<String>>>,
1067    }
1068
1069    impl ProxyTaskCustom {
1070        fn new() -> Self {
1071            Self {
1072                header: RequestHeader::build("GET", b"/", None).unwrap(),
1073                enabled: false,
1074                tasks: Vec::new(),
1075                shutdown_calls: Arc::new(Mutex::new(Vec::new())),
1076            }
1077        }
1078
1079        fn with_shutdown_calls(shutdown_calls: Arc<Mutex<Vec<String>>>) -> Self {
1080            Self {
1081                shutdown_calls,
1082                ..Self::new()
1083            }
1084        }
1085    }
1086
1087    #[async_trait]
1088    impl SessionCustom for ProxyTaskCustom {
1089        fn req_header(&self) -> &RequestHeader {
1090            &self.header
1091        }
1092
1093        fn req_header_mut(&mut self) -> &mut RequestHeader {
1094            &mut self.header
1095        }
1096
1097        async fn read_body_bytes(&mut self) -> Result<Option<Bytes>> {
1098            unreachable!("not used by proxy task dispatch test")
1099        }
1100
1101        async fn drain_request_body(&mut self) -> Result<()> {
1102            unreachable!("not used by proxy task dispatch test")
1103        }
1104
1105        async fn write_response_header(
1106            &mut self,
1107            _resp: Box<ResponseHeader>,
1108            _end: bool,
1109        ) -> Result<()> {
1110            unreachable!("not used by proxy task dispatch test")
1111        }
1112
1113        async fn write_response_header_ref(
1114            &mut self,
1115            _resp: &ResponseHeader,
1116            _end: bool,
1117        ) -> Result<()> {
1118            unreachable!("not used by proxy task dispatch test")
1119        }
1120
1121        async fn write_body(&mut self, _data: Bytes, _end: bool) -> Result<()> {
1122            unreachable!("not used by proxy task dispatch test")
1123        }
1124
1125        async fn write_trailers(&mut self, _trailers: HeaderMap) -> Result<()> {
1126            unreachable!("not used by proxy task dispatch test")
1127        }
1128
1129        async fn response_duplex_vec(&mut self, _tasks: Vec<HttpTask>) -> Result<bool> {
1130            unreachable!("not used by proxy task dispatch test")
1131        }
1132
1133        fn proxy_tasks_enabled(&self) -> bool {
1134            self.enabled
1135        }
1136
1137        fn set_proxy_tasks_enabled(&mut self, enabled: bool) {
1138            self.enabled = enabled;
1139        }
1140
1141        fn send_proxy_task(&mut self, task: HttpTask) {
1142            self.tasks.push(task);
1143        }
1144
1145        fn has_pending_proxy_tasks(&self) -> bool {
1146            !self.tasks.is_empty()
1147        }
1148
1149        async fn write_proxy_tasks(&mut self) -> Result<bool> {
1150            self.tasks.clear();
1151            Ok(true)
1152        }
1153
1154        fn set_read_timeout(&mut self, _timeout: Option<Duration>) {
1155            unreachable!("not used by proxy task dispatch test")
1156        }
1157
1158        fn get_read_timeout(&self) -> Option<Duration> {
1159            unreachable!("not used by proxy task dispatch test")
1160        }
1161
1162        fn set_write_timeout(&mut self, _timeout: Option<Duration>) {
1163            unreachable!("not used by proxy task dispatch test")
1164        }
1165
1166        fn get_write_timeout(&self) -> Option<Duration> {
1167            unreachable!("not used by proxy task dispatch test")
1168        }
1169
1170        fn set_total_drain_timeout(&mut self, _timeout: Option<Duration>) {
1171            unreachable!("not used by proxy task dispatch test")
1172        }
1173
1174        fn get_total_drain_timeout(&self) -> Option<Duration> {
1175            unreachable!("not used by proxy task dispatch test")
1176        }
1177
1178        fn request_summary(&self) -> String {
1179            unreachable!("not used by proxy task dispatch test")
1180        }
1181
1182        fn response_written(&self) -> Option<&ResponseHeader> {
1183            unreachable!("not used by proxy task dispatch test")
1184        }
1185
1186        async fn shutdown(&mut self, code: u32, ctx: &str) {
1187            self.shutdown_calls
1188                .lock()
1189                .unwrap()
1190                .push(format!("shutdown({code}, {ctx})"));
1191        }
1192
1193        async fn abandon(&mut self, ctx: &str) {
1194            self.shutdown_calls
1195                .lock()
1196                .unwrap()
1197                .push(format!("abandon({ctx})"));
1198        }
1199
1200        fn is_body_done(&mut self) -> bool {
1201            unreachable!("not used by proxy task dispatch test")
1202        }
1203
1204        async fn finish(&mut self) -> Result<()> {
1205            unreachable!("not used by proxy task dispatch test")
1206        }
1207
1208        fn is_body_empty(&mut self) -> bool {
1209            unreachable!("not used by proxy task dispatch test")
1210        }
1211
1212        async fn read_body_or_idle(&mut self, _no_body_expected: bool) -> Result<Option<Bytes>> {
1213            unreachable!("not used by proxy task dispatch test")
1214        }
1215
1216        fn body_bytes_sent(&self) -> usize {
1217            unreachable!("not used by proxy task dispatch test")
1218        }
1219
1220        fn body_bytes_read(&self) -> usize {
1221            unreachable!("not used by proxy task dispatch test")
1222        }
1223
1224        fn digest(&self) -> Option<&Digest> {
1225            unreachable!("not used by proxy task dispatch test")
1226        }
1227
1228        fn digest_mut(&mut self) -> Option<&mut Digest> {
1229            unreachable!("not used by proxy task dispatch test")
1230        }
1231
1232        fn client_addr(&self) -> Option<&SocketAddr> {
1233            unreachable!("not used by proxy task dispatch test")
1234        }
1235
1236        fn server_addr(&self) -> Option<&SocketAddr> {
1237            unreachable!("not used by proxy task dispatch test")
1238        }
1239
1240        fn pseudo_raw_h1_request_header(&self) -> Bytes {
1241            unreachable!("not used by proxy task dispatch test")
1242        }
1243
1244        fn enable_retry_buffering(&mut self) {
1245            unreachable!("not used by proxy task dispatch test")
1246        }
1247
1248        fn retry_buffer_truncated(&self) -> bool {
1249            unreachable!("not used by proxy task dispatch test")
1250        }
1251
1252        fn get_retry_buffer(&self) -> Option<Bytes> {
1253            unreachable!("not used by proxy task dispatch test")
1254        }
1255
1256        async fn finish_custom(&mut self) -> Result<()> {
1257            unreachable!("not used by proxy task dispatch test")
1258        }
1259
1260        fn take_custom_message_reader(
1261            &mut self,
1262        ) -> Option<Box<dyn Stream<Item = Result<Bytes>> + Unpin + Send + Sync + 'static>> {
1263            unreachable!("not used by proxy task dispatch test")
1264        }
1265
1266        fn restore_custom_message_reader(
1267            &mut self,
1268            _reader: Box<dyn Stream<Item = Result<Bytes>> + Unpin + Send + Sync + 'static>,
1269        ) -> Result<()> {
1270            unreachable!("not used by proxy task dispatch test")
1271        }
1272
1273        fn take_custom_message_writer(&mut self) -> Option<Box<dyn CustomMessageWrite>> {
1274            unreachable!("not used by proxy task dispatch test")
1275        }
1276
1277        fn restore_custom_message_writer(
1278            &mut self,
1279            _writer: Box<dyn CustomMessageWrite>,
1280        ) -> Result<()> {
1281            unreachable!("not used by proxy task dispatch test")
1282        }
1283    }
1284}