Skip to main content

serve_net/
http.rs

1//! The HTTP family: one request view and one reply for every HTTP ingress.
2
3use core::fmt;
4use std::time::Duration;
5
6use http_net::{
7    BodyPlan, Headers, Method, OutgoingBody, OwnedRequestHead, RequestHead, ResponseHeadRef,
8    Version,
9};
10
11use crate::Finished;
12use crate::client::{ClientInfo, IngressKind};
13use crate::config::{Limits, Profile, ProxyKind};
14use crate::engine::http1::engine_error;
15use crate::engine::{
16    DetachedRequest, EngineError, Family, HeadContext, Http1, OutBuf, RefusalKind, Service,
17};
18use crate::envelope::Envelope;
19use crate::forwarded::{self, FieldLines, Lines, WalkError};
20use crate::reply::Reply;
21use crate::service::{HeadAction, Outcome, UpgradeTarget, UpgradedConn, WorkClass};
22
23/// The reply an HTTP service writes.
24pub type HttpReply = Reply<HttpFamily>;
25
26/// The HTTP family: HTTP/1.1 today, FastCGI and HTTP/2 later, all producing
27/// [`HttpHead`], [`HttpRequest`], and [`HttpReply`].
28#[derive(Clone, Copy, Debug, Default)]
29pub struct HttpFamily;
30
31/// A request head, borrowed from the engine's buffer.
32///
33/// Every accessor is a slice of the bytes that arrived. `authority` is the
34/// normalized authority: the trusted proxy's when `trust_host` is on, else
35/// the absolute-form authority or the `Host` field.
36#[derive(Clone, Copy)]
37pub struct HttpHead<'a> {
38    raw: RequestHead<'a>,
39    client: ClientInfo,
40    authority: Option<&'a str>,
41}
42
43impl<'a> HttpHead<'a> {
44    /// The method.
45    #[must_use]
46    pub fn method(&self) -> Method {
47        self.raw.method()
48    }
49
50    /// The method exactly as received.
51    #[must_use]
52    pub fn method_str(&self) -> &'a str {
53        self.raw.method_str()
54    }
55
56    /// The target exactly as received.
57    #[must_use]
58    pub fn target(&self) -> &'a str {
59        self.raw.target()
60    }
61
62    /// The path, percent-encoding kept.
63    #[must_use]
64    pub fn path(&self) -> &'a str {
65        self.raw.path()
66    }
67
68    /// The query, after the first `?`.
69    #[must_use]
70    pub fn query(&self) -> Option<&'a str> {
71        self.raw.query()
72    }
73
74    /// The protocol version.
75    #[must_use]
76    pub fn version(&self) -> Version {
77        self.raw.version()
78    }
79
80    /// The first field with this name (ASCII case-insensitive).
81    #[must_use]
82    pub fn header(&self, name: &str) -> Option<&'a [u8]> {
83        self.raw.header(name)
84    }
85
86    /// The first field with this name, when it is UTF-8.
87    #[must_use]
88    pub fn header_str(&self, name: &str) -> Option<&'a str> {
89        self.raw.header_str(name)
90    }
91
92    /// Every field with this name, in order.
93    pub fn header_all<'n>(&self, name: &'n str) -> impl Iterator<Item = &'a [u8]> + use<'a, 'n> {
94        self.raw.header_all(name)
95    }
96
97    /// Every field in arrival order.
98    #[must_use]
99    pub fn headers(&self) -> Fields<'a> {
100        Fields {
101            inner: FieldSource::Head(self.raw.headers()),
102        }
103    }
104
105    /// The normalized authority.
106    #[must_use]
107    pub fn authority(&self) -> Option<&'a str> {
108        self.authority
109    }
110
111    /// The request's client.
112    #[must_use]
113    pub fn client(&self) -> &ClientInfo {
114        &self.client
115    }
116
117    /// The declared body length.
118    #[must_use]
119    pub fn content_length(&self) -> Option<u64> {
120        self.raw.content_length()
121    }
122
123    /// Whether the client waits for `100 Continue` before its body.
124    #[must_use]
125    pub fn expects_continue(&self) -> bool {
126        self.raw.expects_continue()
127    }
128
129    /// Whether the request offers an upgrade (never true for `h2c` alone).
130    #[must_use]
131    pub fn is_upgrade(&self) -> bool {
132        self.raw.is_upgrade()
133    }
134}
135
136impl fmt::Debug for HttpHead<'_> {
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        // http-net's Debug redacts credential fields.
139        f.debug_struct("HttpHead")
140            .field("head", &self.raw)
141            .field("client", &self.client)
142            .finish()
143    }
144}
145
146/// Every field of a head in arrival order: `(name, value)`.
147#[derive(Clone)]
148pub struct Fields<'a> {
149    inner: FieldSource<'a>,
150}
151
152#[derive(Clone)]
153enum FieldSource<'a> {
154    Head(Headers<'a>),
155    Copy(&'a [u8], core::slice::Iter<'a, (Span, Span)>),
156}
157
158impl<'a> Iterator for Fields<'a> {
159    type Item = (&'a str, &'a [u8]);
160    fn next(&mut self) -> Option<Self::Item> {
161        match &mut self.inner {
162            FieldSource::Head(h) => h.next(),
163            FieldSource::Copy(bytes, spans) => {
164                let (name, value) = spans.next()?;
165                let name = core::str::from_utf8(name.of(bytes)).unwrap_or("");
166                Some((name, value.of(bytes)))
167            }
168        }
169    }
170    fn size_hint(&self) -> (usize, Option<usize>) {
171        match &self.inner {
172            FieldSource::Head(h) => h.size_hint(),
173            FieldSource::Copy(_, spans) => spans.size_hint(),
174        }
175    }
176}
177
178impl ExactSizeIterator for Fields<'_> {}
179
180/// The request body.
181#[non_exhaustive]
182#[derive(Clone, Copy, Debug, PartialEq, Eq)]
183pub enum HttpBody<'a> {
184    /// No body.
185    Empty,
186    /// The whole buffered body.
187    Full(&'a [u8]),
188    /// One piece of a body read under `BodyPolicy::Stream`.
189    Chunk {
190        /// The bytes of this piece, possibly none.
191        bytes: &'a [u8],
192        /// Whether the body ends here.
193        last: bool,
194    },
195}
196
197impl<'a> HttpBody<'a> {
198    /// The body bytes (empty for `Empty`).
199    #[must_use]
200    pub fn bytes(&self) -> &'a [u8] {
201        match self {
202            HttpBody::Empty => &[],
203            HttpBody::Full(b) | HttpBody::Chunk { bytes: b, .. } => b,
204        }
205    }
206}
207
208/// The request an HTTP service answers.
209#[derive(Clone, Copy)]
210pub struct HttpRequest<'a> {
211    head: HttpHead<'a>,
212    body: &'a [u8],
213    /// For one piece of a streamed body: whether it is the last.
214    chunk: Option<bool>,
215}
216
217impl<'a> HttpRequest<'a> {
218    /// The head.
219    #[must_use]
220    pub fn head(&self) -> &HttpHead<'a> {
221        &self.head
222    }
223
224    /// The method.
225    #[must_use]
226    pub fn method(&self) -> Method {
227        self.head.method()
228    }
229
230    /// The path.
231    #[must_use]
232    pub fn path(&self) -> &'a str {
233        self.head.path()
234    }
235
236    /// The query.
237    #[must_use]
238    pub fn query(&self) -> Option<&'a str> {
239        self.head.query()
240    }
241
242    /// The first field with this name.
243    #[must_use]
244    pub fn header(&self, name: &str) -> Option<&'a [u8]> {
245        self.head.header(name)
246    }
247
248    /// The request's client.
249    #[must_use]
250    pub fn client(&self) -> &ClientInfo {
251        self.head.client()
252    }
253
254    /// The body.
255    #[must_use]
256    pub fn body(&self) -> HttpBody<'a> {
257        match self.chunk {
258            Some(last) => HttpBody::Chunk {
259                bytes: self.body,
260                last,
261            },
262            None if self.body.is_empty() => HttpBody::Empty,
263            None => HttpBody::Full(self.body),
264        }
265    }
266
267    /// The buffered body bytes, or empty.
268    #[must_use]
269    pub fn body_bytes(&self) -> &'a [u8] {
270        self.body
271    }
272
273    /// An owned, `Send` copy of the head, for work that outlives `call`.
274    #[must_use]
275    pub fn detach_head(&self) -> DetachedHead {
276        DetachedHead::of(&self.head)
277    }
278}
279
280/// A request a pool thread answers: the head, the normalized facts, the body.
281struct OwnedRequest {
282    head: OwnedRequestHead,
283    client: ClientInfo,
284    authority: Option<Box<str>>,
285    body: Box<[u8]>,
286}
287
288impl DetachedRequest<HttpFamily> for OwnedRequest {
289    fn with(&self, call: &mut dyn FnMut(&HttpRequest<'_>)) {
290        call(&HttpRequest {
291            head: HttpHead {
292                raw: self.head.view(),
293                client: self.client,
294                authority: self.authority.as_deref(),
295            },
296            body: &self.body,
297            chunk: None,
298        });
299    }
300}
301
302/// Where a value sits in a [`DetachedHead`]'s bytes.
303#[derive(Clone, Copy, Debug)]
304struct Span {
305    start: u32,
306    len: u32,
307}
308
309impl Span {
310    fn of(self, bytes: &[u8]) -> &[u8] {
311        let start = self.start as usize;
312        bytes.get(start..start + self.len as usize).unwrap_or(&[])
313    }
314}
315
316/// An owned, `Send` copy of a request head with the same accessors as
317/// [`HttpHead`], for work that outlives `call`.
318///
319/// ```
320/// let site = serve_net::handler(|req, reply| {
321///     let head = req.detach_head();
322///     let worker = std::thread::spawn(move || head.path().to_owned());
323///     reply.text(200, &worker.join().unwrap());
324/// });
325/// let reply = serve_net::testing::respond(&site, b"GET /jobs HTTP/1.1\r\nHost: a\r\n\r\n");
326/// assert_eq!(reply.text(), "/jobs");
327/// ```
328pub struct DetachedHead {
329    bytes: Vec<u8>,
330    method: Method,
331    version: Version,
332    method_str: Span,
333    target: Span,
334    path: Span,
335    query: Option<Span>,
336    fields: Vec<(Span, Span)>,
337}
338
339/// Fields whose values `Debug` never prints.
340const CREDENTIALS: [&str; 4] = [
341    "authorization",
342    "proxy-authorization",
343    "cookie",
344    "set-cookie",
345];
346
347impl DetachedHead {
348    fn of(head: &HttpHead<'_>) -> Self {
349        let mut bytes = Vec::with_capacity(512);
350        let mut put = |value: &[u8]| {
351            let start = bytes.len() as u32;
352            bytes.extend_from_slice(value);
353            Span {
354                start,
355                len: value.len() as u32,
356            }
357        };
358        let method_str = put(head.method_str().as_bytes());
359        let target = put(head.target().as_bytes());
360        let path = put(head.path().as_bytes());
361        let query = head.query().map(|q| put(q.as_bytes()));
362        let fields = head
363            .headers()
364            .map(|(name, value)| (put(name.as_bytes()), put(value)))
365            .collect();
366        DetachedHead {
367            bytes,
368            method: head.method(),
369            version: head.version(),
370            method_str,
371            target,
372            path,
373            query,
374            fields,
375        }
376    }
377
378    fn text(&self, span: Span) -> &str {
379        core::str::from_utf8(span.of(&self.bytes)).unwrap_or("")
380    }
381
382    /// The method.
383    #[must_use]
384    pub fn method(&self) -> Method {
385        self.method
386    }
387
388    /// The method exactly as received.
389    #[must_use]
390    pub fn method_str(&self) -> &str {
391        self.text(self.method_str)
392    }
393
394    /// The target exactly as received.
395    #[must_use]
396    pub fn target(&self) -> &str {
397        self.text(self.target)
398    }
399
400    /// The path, percent-encoding kept.
401    #[must_use]
402    pub fn path(&self) -> &str {
403        self.text(self.path)
404    }
405
406    /// The query, after the first `?`.
407    #[must_use]
408    pub fn query(&self) -> Option<&str> {
409        self.query.map(|q| self.text(q))
410    }
411
412    /// The protocol version.
413    #[must_use]
414    pub fn version(&self) -> Version {
415        self.version
416    }
417
418    /// The first field with this name (ASCII case-insensitive).
419    #[must_use]
420    pub fn header(&self, name: &str) -> Option<&[u8]> {
421        self.headers()
422            .find(|(n, _)| n.eq_ignore_ascii_case(name))
423            .map(|(_, value)| value)
424    }
425
426    /// Every field with this name, in order.
427    pub fn header_all<'s>(&'s self, name: &'s str) -> impl Iterator<Item = &'s [u8]> + 's {
428        self.headers()
429            .filter(move |(n, _)| n.eq_ignore_ascii_case(name))
430            .map(|(_, value)| value)
431    }
432
433    /// Every field in arrival order.
434    #[must_use]
435    pub fn headers(&self) -> Fields<'_> {
436        Fields {
437            inner: FieldSource::Copy(&self.bytes, self.fields.iter()),
438        }
439    }
440}
441
442impl fmt::Debug for DetachedHead {
443    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444        let mut d = f.debug_struct("DetachedHead");
445        d.field("method", &self.method_str())
446            .field("target", &self.target());
447        let fields: Vec<(&str, &str)> = self
448            .headers()
449            .map(|(n, v)| {
450                let secret = CREDENTIALS.iter().any(|c| n.eq_ignore_ascii_case(c));
451                let value = if secret {
452                    "<redacted>"
453                } else {
454                    core::str::from_utf8(v).unwrap_or("<binary>")
455                };
456                (n, value)
457            })
458            .collect();
459        d.field("fields", &fields).finish()
460    }
461}
462
463impl fmt::Debug for HttpRequest<'_> {
464    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
465        f.debug_struct("HttpRequest")
466            .field("head", &self.head)
467            .field("body_len", &self.body.len())
468            .finish()
469    }
470}
471
472/// The most fields one reply may carry; more turns it into the 500 refusal.
473const MAX_FIELDS: usize = 64;
474
475/// The HTTP family's reply data. Services use [`HttpReply`]'s methods.
476#[derive(Default)]
477pub struct HttpParts {
478    status: u16,
479    names: Vec<u8>,
480    values: Vec<u8>,
481    spans: Vec<(u32, u32, u32, u32)>,
482    body: Vec<u8>,
483    body_static: Option<&'static [u8]>,
484    close: bool,
485    retry_after: Option<u64>,
486    invalid: bool,
487    /// The service opened a streamed reply.
488    streaming: bool,
489    /// Bytes of a streamed reply in earlier parts.
490    sent: u64,
491}
492
493impl HttpParts {
494    /// Keeps the stream open and drops the part already encoded.
495    fn next_part(&mut self, wipe: bool) {
496        self.sent += self.body.len() as u64;
497        if wipe {
498            crate::engine::wipe_bytes(&mut self.values);
499            crate::engine::wipe_bytes(&mut self.body);
500        }
501        // The head left with the first part: fields set again go nowhere.
502        self.names.clear();
503        self.values.clear();
504        self.spans.clear();
505        self.body.clear();
506    }
507
508    fn clear(&mut self, wipe: bool) {
509        if wipe {
510            crate::engine::wipe_bytes(&mut self.values);
511            crate::engine::wipe_bytes(&mut self.body);
512        }
513        self.status = 0;
514        self.names.clear();
515        self.values.clear();
516        self.spans.clear();
517        self.body.clear();
518        self.body_static = None;
519        self.close = false;
520        self.retry_after = None;
521        self.invalid = false;
522        self.streaming = false;
523        self.sent = 0;
524    }
525}
526
527impl fmt::Debug for HttpParts {
528    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529        // Field values may hold credentials (set-cookie): only names and sizes.
530        let names: Vec<&str> = self
531            .spans
532            .iter()
533            .map(|&(s, e, _, _)| {
534                core::str::from_utf8(&self.names[s as usize..e as usize]).unwrap_or("?")
535            })
536            .collect();
537        f.debug_struct("HttpParts")
538            .field("status", &self.status)
539            .field("fields", &names)
540            .field(
541                "body_len",
542                &self.body_static.map_or(self.body.len(), <[u8]>::len),
543            )
544            .finish()
545    }
546}
547
548/// A reply sent in parts; see [`HttpReply::stream`].
549#[derive(Debug)]
550pub struct ReplyStream<'a> {
551    parts: &'a mut HttpParts,
552}
553
554impl ReplyStream<'_> {
555    /// Adds bytes to this part. They are copied, and leave when `call` returns.
556    pub fn send(&mut self, bytes: &[u8]) -> &mut Self {
557        self.parts.body.extend_from_slice(bytes);
558        self
559    }
560
561    /// The bytes sent in earlier parts: where a service that keeps no state
562    /// of its own picks up.
563    #[must_use]
564    pub fn sent(&self) -> u64 {
565        self.parts.sent
566    }
567}
568
569impl Reply<HttpFamily> {
570    /// Sends the reply in parts with chunked encoding (close-delimited to an
571    /// HTTP/1.0 client), for bodies too large to hold or not yet known.
572    ///
573    /// Call it in every `call` of the reply and add the next part. Return
574    /// [`Outcome::More`] to be called again once the client has taken this
575    /// part, so a slow reader holds back the service and not memory; return
576    /// [`Outcome::Done`] with the last part. The status and fields go with
577    /// the first part, and each part passes `CheckpointAt::BeforeReply`.
578    ///
579    /// Once the head has left no refusal can follow it, so a panic, a denial,
580    /// a timeout, or a service error closes the connection abortively and
581    /// the client sees a truncated body. A streamed reply cannot be deferred
582    /// and stays on the worker: it does not run through `Offload`.
583    ///
584    /// Cost: one call and one copy per part, nothing per byte held back.
585    ///
586    /// ```
587    /// use serve_net::Outcome;
588    /// const BLOCK: &[u8] = &[b'x'; 4096];
589    ///
590    /// struct Download;
591    ///
592    /// impl serve_net::HttpService for Download {
593    ///     fn call(
594    ///         &self,
595    ///         _req: &serve_net::HttpRequest<'_>,
596    ///         _env: &serve_net::Envelope,
597    ///         reply: &mut serve_net::HttpReply,
598    ///     ) -> Outcome {
599    ///         reply.header("content-type", "application/octet-stream");
600    ///         let mut stream = reply.stream();
601    ///         stream.send(BLOCK);
602    ///         if stream.sent() + 4096 < 1 << 20 { Outcome::More } else { Outcome::Done }
603    ///     }
604    /// }
605    /// # let _ = Download;
606    /// ```
607    pub fn stream(&mut self) -> ReplyStream<'_> {
608        self.parts.streaming = true;
609        self.parts.body_static = None;
610        ReplyStream {
611            parts: &mut self.parts,
612        }
613    }
614
615    /// Sets the status (default 200).
616    pub fn status(&mut self, status: u16) -> &mut Self {
617        self.parts.status = status;
618        self
619    }
620
621    /// Adds a field. An invalid name or value (a CR or LF, a control byte, a
622    /// framing field such as `content-length`) turns the reply into the 500
623    /// refusal when it is written.
624    pub fn header(&mut self, name: &str, value: impl AsRef<[u8]>) -> &mut Self {
625        let p = &mut self.parts;
626        if p.spans.len() >= MAX_FIELDS {
627            p.invalid = true;
628            return self;
629        }
630        let value = value.as_ref();
631        let (ns, vs) = (p.names.len() as u32, p.values.len() as u32);
632        p.names.extend_from_slice(name.as_bytes());
633        p.values.extend_from_slice(value);
634        p.spans
635            .push((ns, p.names.len() as u32, vs, p.values.len() as u32));
636        self
637    }
638
639    /// Sets the body, copied into the reply's reused buffer.
640    pub fn body(&mut self, bytes: &[u8]) -> &mut Self {
641        let p = &mut self.parts;
642        p.body.clear();
643        p.body.extend_from_slice(bytes);
644        p.body_static = None;
645        self
646    }
647
648    /// Sets a static body, not copied.
649    pub fn body_static(&mut self, bytes: &'static [u8]) -> &mut Self {
650        self.parts.body.clear();
651        self.parts.body_static = Some(bytes);
652        self
653    }
654
655    /// Status, `content-type: text/plain; charset=utf-8`, and the text as body.
656    pub fn text(&mut self, status: u16, text: &str) -> &mut Self {
657        self.status(status)
658            .header("content-type", "text/plain; charset=utf-8")
659            .body(text.as_bytes())
660    }
661
662    /// Status, `content-type: text/html; charset=utf-8`, and the HTML as body.
663    pub fn html(&mut self, status: u16, html: &str) -> &mut Self {
664        self.status(status)
665            .header("content-type", "text/html; charset=utf-8")
666            .body(html.as_bytes())
667    }
668
669    /// Ends the connection after this reply.
670    pub fn close(&mut self) -> &mut Self {
671        self.parts.close = true;
672        self
673    }
674
675    /// Adds `Retry-After` in whole seconds (at least 1).
676    pub fn retry_after(&mut self, after: Duration) -> &mut Self {
677        self.parts.retry_after = Some(after.as_secs().max(1));
678        self
679    }
680}
681
682/// Reads forwarding fields from an http-net head.
683impl<'h> FieldLines<'h> for RequestHead<'h> {
684    fn field_lines(&self, name: &str, out: &mut Lines<'h>) -> Result<(), WalkError> {
685        for v in self.header_all(name) {
686            out.push(v)?;
687        }
688        Ok(())
689    }
690}
691
692impl Family for HttpFamily {
693    type Engine = Http1;
694    type Head<'a> = HttpHead<'a>;
695    type Request<'a> = HttpRequest<'a>;
696    type Parts = HttpParts;
697
698    fn engine(&self, profile: &Profile, limits: &Limits) -> Http1 {
699        let engine_limits = limits
700            .engine
701            .with_max_body(limits.max_body.min(limits.engine.max_body()));
702        Http1::new(engine_limits, profile.wipe_buffers)
703    }
704
705    fn head<'a>(
706        &self,
707        raw: RequestHead<'a>,
708        cx: &HeadContext<'a>,
709    ) -> Result<(HttpHead<'a>, ClientInfo), EngineError> {
710        let base = *cx.client;
711        let ingress_error = EngineError {
712            kind: RefusalKind::Ingress,
713            status: 400,
714        };
715        let Some(proxy) = cx.proxy else {
716            return Ok((
717                HttpHead {
718                    raw,
719                    client: base,
720                    authority: raw.host(),
721                },
722                base,
723            ));
724        };
725        match proxy.kind {
726            ProxyKind::Headers(source) => {
727                if let Some(client) = cx.resolved {
728                    // Built again for the call: the walk already ran at the
729                    // head. The host is the proxy's only when that walk went
730                    // through a trusted hop; from any other peer the
731                    // forwarded fields are the client's own words (T-17).
732                    let host = if proxy.trust_host && client.ingress() == IngressKind::Forwarded {
733                        forwarded::trusted_host(source, &raw)
734                    } else {
735                        None
736                    };
737                    let authority = host.or_else(|| raw.host());
738                    return Ok((
739                        HttpHead {
740                            raw,
741                            client,
742                            authority,
743                        },
744                        client,
745                    ));
746                }
747                // A Unix socket peer has no address; it passed its credential
748                // check, so the walk starts from a trusted hop.
749                let unix = base.ingress() == IngressKind::Unix;
750                let peer = match base.peer() {
751                    Some(p) => Some(p),
752                    None if unix => None,
753                    None => return Err(ingress_error),
754                };
755                let rules = forwarded::Rules {
756                    source,
757                    trusted: &proxy.trusted,
758                    max_hops: proxy.max_hops,
759                    missing: proxy.missing,
760                    unknown: proxy.unknown,
761                    trust_scheme: proxy.trust_scheme,
762                    trust_host: proxy.trust_host,
763                };
764                let found = forwarded::resolve_from(
765                    peer.map(|p| p.ip()),
766                    peer.map_or(0, |p| p.port()),
767                    &rules,
768                    &raw,
769                )
770                .map_err(|_| ingress_error)?;
771                let client = if found.forwarded {
772                    base.behind_proxy(found.client, found.port, found.hops, IngressKind::Forwarded)
773                        .with_scheme(found.scheme.unwrap_or(cx.declared_scheme))
774                } else {
775                    base
776                };
777                let authority = found.host.or_else(|| raw.host());
778                Ok((
779                    HttpHead {
780                        raw,
781                        client,
782                        authority,
783                    },
784                    client,
785                ))
786            }
787            ProxyKind::ProxyProtocol(_) => {
788                // The session built the client from net-io's PROXY facts.
789                let client = base;
790                let tlv = if proxy.trust_host {
791                    cx.proxy_facts
792                        .and_then(|f| f.authority())
793                        .filter(|a| forwarded::valid_authority(a.as_bytes()))
794                } else {
795                    None
796                };
797                Ok((
798                    HttpHead {
799                        raw,
800                        client,
801                        authority: tlv.or_else(|| raw.host()),
802                    },
803                    client,
804                ))
805            }
806        }
807    }
808
809    fn request<'a>(&self, head: HttpHead<'a>, body: &'a [u8]) -> HttpRequest<'a> {
810        HttpRequest {
811            head,
812            body,
813            chunk: None,
814        }
815    }
816
817    fn request_chunk<'a>(&self, head: HttpHead<'a>, body: &'a [u8], last: bool) -> HttpRequest<'a> {
818        HttpRequest {
819            head,
820            body,
821            chunk: Some(last),
822        }
823    }
824
825    fn reply_stream(&self, parts: &HttpParts) -> bool {
826        parts.streaming
827    }
828
829    fn respond_stream(
830        &self,
831        engine: &mut Http1,
832        parts: &mut HttpParts,
833        first: bool,
834        last: bool,
835        unix_secs: u64,
836        out: &mut OutBuf,
837    ) -> Result<u16, EngineError> {
838        let mut status = 0;
839        if first {
840            let (written, plan) = encode(engine, parts, true, unix_secs, out)?;
841            status = written;
842            if !matches!(plan, BodyPlan::Stream) {
843                // `HEAD`, or a status without a body: the head was the reply.
844                parts.streaming = false;
845                return Ok(status);
846            }
847        }
848        if !parts.body.is_empty() {
849            engine
850                .conn
851                .send_body(&parts.body, &mut out.bytes)
852                .map_err(engine_error)?;
853        }
854        if last {
855            engine.conn.end_body(&mut out.bytes).map_err(engine_error)?;
856        }
857        Ok(status)
858    }
859
860    fn next_stream_part(&self, parts: &mut HttpParts, wipe: bool) {
861        parts.next_part(wipe);
862    }
863
864    fn detach(&self, request: &HttpRequest<'_>) -> Option<Box<dyn DetachedRequest<Self>>> {
865        Some(Box::new(OwnedRequest {
866            head: request.head.raw.to_owned(),
867            client: request.head.client,
868            authority: request.head.authority.map(Box::from),
869            body: Box::from(request.body),
870        }))
871    }
872
873    fn new_parts(&self) -> HttpParts {
874        HttpParts::default()
875    }
876
877    fn clear_parts(&self, parts: &mut HttpParts, wipe: bool) {
878        parts.clear(wipe);
879    }
880
881    fn respond(
882        &self,
883        engine: &mut Http1,
884        parts: &mut HttpParts,
885        unix_secs: u64,
886        out: &mut OutBuf,
887    ) -> Result<u16, EngineError> {
888        encode(engine, parts, false, unix_secs, out).map(|(status, _)| status)
889    }
890
891    fn upgrade(
892        &self,
893        engine: &mut Http1,
894        target: &UpgradeTarget,
895        unix_secs: u64,
896        out: &mut OutBuf,
897    ) -> Result<(), EngineError> {
898        let _ = (&engine, unix_secs, &out);
899        match *target {
900            #[cfg(feature = "ws")]
901            UpgradeTarget::WebSocket(ref t) => crate::ws::switch_http1(engine, t, unix_secs, out),
902        }
903    }
904}
905
906/// Writes the reply's head, and its body unless `chunked`.
907fn encode(
908    engine: &mut Http1,
909    parts: &HttpParts,
910    chunked: bool,
911    unix_secs: u64,
912    out: &mut OutBuf,
913) -> Result<(u16, BodyPlan), EngineError> {
914    if parts.invalid {
915        return Err(EngineError {
916            kind: RefusalKind::Internal,
917            status: 500,
918        });
919    }
920    let status = if parts.status == 0 { 200 } else { parts.status };
921    let mut fields: [(&str, &[u8]); MAX_FIELDS + 1] = [("", &[]); MAX_FIELDS + 1];
922    let mut n = 0;
923    for &(ns, ne, vs, ve) in &parts.spans {
924        let Ok(name) = core::str::from_utf8(&parts.names[ns as usize..ne as usize]) else {
925            return Err(EngineError {
926                kind: RefusalKind::Internal,
927                status: 500,
928            });
929        };
930        fields[n] = (name, &parts.values[vs as usize..ve as usize]);
931        n += 1;
932    }
933    let mut digits = [0u8; 20];
934    if let Some(secs) = parts.retry_after {
935        fields[n] = ("retry-after", format_secs(secs, &mut digits));
936        n += 1;
937    }
938    let body: &[u8] = match parts.body_static {
939        Some(b) => b,
940        None => &parts.body,
941    };
942    let outgoing = if chunked {
943        OutgoingBody::Chunked
944    } else if body.is_empty() {
945        OutgoingBody::Empty
946    } else {
947        OutgoingBody::Full(body.len() as u64)
948    };
949    let mut head = ResponseHeadRef::new(status, &fields[..n], outgoing);
950    head.close = parts.close;
951    let date = engine.dates.update(unix_secs);
952    let start = out.len();
953    match engine.conn.write_head(&head, Some(date), out) {
954        Ok(plan) => {
955            if matches!(plan, BodyPlan::Raw) {
956                out.push(body);
957            }
958            Ok((status, plan))
959        }
960        Err(e) => {
961            out.bytes.truncate(start);
962            let mut err = engine_error(e);
963            err.kind = RefusalKind::Internal;
964            err.status = 500;
965            Err(err)
966        }
967    }
968}
969
970fn format_secs(mut n: u64, buf: &mut [u8; 20]) -> &[u8] {
971    let mut i = buf.len();
972    loop {
973        i -= 1;
974        buf[i] = b'0' + (n % 10) as u8;
975        n /= 10;
976        if n == 0 {
977            break;
978        }
979    }
980    &buf[i..]
981}
982
983/// The contract between serve-net and an HTTP service, in the order serve-net
984/// calls it per request: `head`, then (after admission) `call`, then `done`.
985pub trait HttpService: Send + Sync {
986    /// How the service behaves.
987    const WORK: WorkClass = WorkClass::Quick;
988
989    /// The head is complete; before admission and before any body byte.
990    fn head(&self, head: &HttpHead<'_>, env: &mut Envelope) -> HeadAction {
991        let _ = (head, env);
992        HeadAction::Proceed
993    }
994
995    /// The request is complete.
996    fn call(&self, request: &HttpRequest<'_>, env: &Envelope, reply: &mut HttpReply) -> Outcome;
997
998    /// After the 101 for an upgrade this service asked for in `head` left,
999    /// and after `done` for that request. The conversation itself belongs to
1000    /// the upgrade target (a `WebSocketService`, feature `ws`).
1001    fn upgraded(&self, env: &Envelope, conn: UpgradedConn) {
1002        let _ = (env, conn);
1003    }
1004
1005    /// Exactly once per request that reached `head`, on every path.
1006    fn done(&self, env: &Envelope, finished: &Finished) {
1007        let _ = (env, finished);
1008    }
1009}
1010
1011impl<S: HttpService> Service<HttpFamily> for S {
1012    const WORK: WorkClass = <S as HttpService>::WORK;
1013    fn head(&self, head: &HttpHead<'_>, env: &mut Envelope) -> HeadAction {
1014        HttpService::head(self, head, env)
1015    }
1016    fn call(&self, request: &HttpRequest<'_>, env: &Envelope, reply: &mut HttpReply) -> Outcome {
1017        HttpService::call(self, request, env, reply)
1018    }
1019    fn upgraded(&self, env: &Envelope, conn: UpgradedConn) {
1020        HttpService::upgraded(self, env, conn);
1021    }
1022    fn done(&self, env: &Envelope, finished: &Finished) {
1023        HttpService::done(self, env, finished);
1024    }
1025}
1026
1027/// A closure as an [`HttpService`].
1028pub struct Handler<F> {
1029    f: F,
1030}
1031
1032/// Starts an HTTP/1.1 server and returns it running: one direct TCP listener
1033/// per resolved address (`http-0`, `http-1`, ...), the default limits,
1034/// keep-alive, workers, and hooks, and net-io's `AllowAll` gate.
1035///
1036/// ```no_run
1037/// let server = serve_net::http("127.0.0.1:8080", |req, reply| {
1038///     match req.path() {
1039///         "/" => { reply.html(200, "<h1>It works</h1>"); }
1040///         _ => { reply.text(404, "not found"); }
1041///     }
1042/// })?;
1043/// server.wait();
1044/// # Ok::<(), serve_net::ServeError>(())
1045/// ```
1046///
1047/// # Errors
1048///
1049/// [`ServeError::Bind`](crate::ServeError::Bind) naming the address;
1050/// [`ServeError::Config`](crate::ServeError::Config) with
1051/// `RuleId::AddressResolve` when the address resolved to nothing.
1052pub fn http<A, F>(addr: A, handler: F) -> Result<crate::Running, crate::ServeError>
1053where
1054    A: std::net::ToSocketAddrs,
1055    F: Fn(&HttpRequest<'_>, &mut HttpReply) + Send + Sync + 'static,
1056{
1057    tier1(addr, None, handler)
1058}
1059
1060/// As [`http`], behind a reverse proxy on the same host: the real client
1061/// comes from `X-Forwarded-For`, walked right to left and believed only when
1062/// the socket peer is in `trusted` (addresses and CIDR blocks separated by
1063/// commas or whitespace, `"127.0.0.1, ::1"`). A trusted peer that sends no
1064/// `X-Forwarded-For` is refused with 400; scheme and host are not taken from
1065/// the proxy (Tier 2 has `trust_scheme` and `trust_host`).
1066///
1067/// ```
1068/// // Refused at start-up: a trusting listener on every interface.
1069/// let err = serve_net::http_behind_proxy("0.0.0.0:8080", "127.0.0.1", |_req, reply| {
1070///     reply.text(200, "x");
1071/// })
1072/// .unwrap_err();
1073/// assert!(err.to_string().contains("public"));
1074/// ```
1075///
1076/// # Errors
1077///
1078/// As [`http`], plus [`ServeError::Config`](crate::ServeError::Config) with
1079/// `RuleId::PublicBind`, `TrustParse`, `TrustEmpty`, `TrustTooBroad`, or
1080/// `TrustWildcard`.
1081pub fn http_behind_proxy<A, F>(
1082    addr: A,
1083    trusted: &str,
1084    handler: F,
1085) -> Result<crate::Running, crate::ServeError>
1086where
1087    A: std::net::ToSocketAddrs,
1088    F: Fn(&HttpRequest<'_>, &mut HttpReply) + Send + Sync + 'static,
1089{
1090    use crate::error::{ConfigError, ConfigErrors, RuleId, Subject};
1091    let trusted = crate::TrustedProxies::parse(trusted).map_err(|e| {
1092        let error = match e {
1093            crate::AddrError::Empty => ConfigError::new(
1094                RuleId::TrustEmpty,
1095                Subject::Listener("http-0".to_owned()),
1096                "the trusted proxy list is empty",
1097                "list the proxies' addresses, for example \"127.0.0.1, ::1\"",
1098            ),
1099            _ => ConfigError::new(
1100                RuleId::TrustParse,
1101                Subject::Listener("http-0".to_owned()),
1102                "the trusted proxy list does not parse",
1103                "use addresses or CIDR blocks separated by commas, for example \"10.0.0.0/8\"",
1104            ),
1105        };
1106        crate::ServeError::Config(
1107            ConfigErrors::from_vec(vec![error]).unwrap_or_else(|| unreachable!()),
1108        )
1109    })?;
1110    tier1(addr, Some(trusted), handler)
1111}
1112
1113/// The listeners of Tier 1: one per resolved address, `http-0`, `http-1`, ...
1114fn tier1<A, F>(
1115    addr: A,
1116    trusted: Option<crate::TrustedProxies>,
1117    handler: F,
1118) -> Result<crate::Running, crate::ServeError>
1119where
1120    A: std::net::ToSocketAddrs,
1121    F: Fn(&HttpRequest<'_>, &mut HttpReply) + Send + Sync + 'static,
1122{
1123    let addrs: Vec<std::net::SocketAddr> = addr
1124        .to_socket_addrs()
1125        .map(Iterator::collect)
1126        .unwrap_or_default();
1127    let spec = |name: &str, a: &[std::net::SocketAddr]| {
1128        let l = crate::ListenerSpec::tcp(name, a);
1129        match &trusted {
1130            None => l,
1131            Some(t) => l.ingress(crate::Ingress::Proxy(crate::ProxySource::forwarded_for(
1132                t.clone(),
1133            ))),
1134        }
1135    };
1136    let mut builder = crate::Server::builder();
1137    if addrs.is_empty() {
1138        // Resolves to nothing: validation names the rule.
1139        builder = builder.listener(spec("http-0", &[]));
1140    }
1141    for (i, a) in addrs.iter().enumerate() {
1142        builder = builder.listener(spec(&format!("http-{i}"), core::slice::from_ref(a)));
1143    }
1144    builder.serve(Handler { f: handler })
1145}
1146
1147/// Turns a closure into an [`HttpService`] where a type is expected; the
1148/// closure needs no annotations.
1149///
1150/// ```
1151/// let site = serve_net::handler(|req, reply| { reply.text(200, req.path()); });
1152/// let reply = serve_net::testing::respond(&site, b"GET /hi HTTP/1.1\r\nHost: a\r\n\r\n");
1153/// assert_eq!(reply.text(), "/hi");
1154/// ```
1155pub fn handler<F>(f: F) -> Handler<F>
1156where
1157    F: Fn(&HttpRequest<'_>, &mut HttpReply) + Send + Sync + 'static,
1158{
1159    Handler { f }
1160}
1161
1162impl<F> HttpService for Handler<F>
1163where
1164    F: Fn(&HttpRequest<'_>, &mut HttpReply) + Send + Sync + 'static,
1165{
1166    fn call(&self, request: &HttpRequest<'_>, _env: &Envelope, reply: &mut HttpReply) -> Outcome {
1167        (self.f)(request, reply);
1168        Outcome::Done
1169    }
1170}
1171
1172impl<F> fmt::Debug for Handler<F> {
1173    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1174        f.write_str("Handler")
1175    }
1176}
1177
1178#[cfg(test)]
1179mod tests {
1180    use super::*;
1181
1182    #[test]
1183    fn test_reply_debug_redacts_values() {
1184        let mut r = HttpReply::new(HttpParts::default());
1185        r.header("set-cookie", "sid=secret").text(200, "x");
1186        let text = format!("{r:?}");
1187        assert!(!text.contains("secret"));
1188        assert!(text.contains("set-cookie"));
1189    }
1190
1191    #[test]
1192    fn test_reply_too_many_fields_is_invalid() {
1193        let mut r = HttpReply::new(HttpParts::default());
1194        for _ in 0..=MAX_FIELDS {
1195            r.header("x-a", "1");
1196        }
1197        assert!(r.parts.invalid);
1198    }
1199
1200    #[test]
1201    fn test_parts_clear_wipes() {
1202        let mut r = HttpReply::new(HttpParts::default());
1203        r.header("x", "secret").body(b"secret");
1204        r.parts.clear(true);
1205        assert!(r.parts.values.is_empty() && r.parts.body.is_empty() && r.parts.spans.is_empty());
1206    }
1207}