char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somrearrange libs into lib and extensions into extsf4a0f5b

main
32.1 KiB946 linesraw
1pub mod file;
2
3use std::collections::HashMap;
4use std::future::Future;
5use std::io;
6use std::pin::Pin;
7use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
8use std::sync::{Arc, Mutex, Weak};
9use std::task::{Context, Poll};
10
11use base64::Engine as _;
12use bytes::Bytes;
13use futures::channel::oneshot;
14use futures::future::BoxFuture;
15use http_body_util::{BodyExt, Full, StreamBody, combinators::UnsyncBoxBody};
16use hyper::body::{Body as HttpBody, Frame, Incoming, SizeHint};
17use hyper::server::conn::http1;
18use hyper::service::service_fn;
19use hyper::{Request, Response, StatusCode};
20use hyper_util::rt::{TokioIo, TokioTimer};
21use sha1::Digest;
22use tokio::sync::{Mutex as AsyncMutex, mpsc};
23use tokio::task::JoinSet;
24use tokio_util::sync::CancellationToken;
25use tokio_util::task::TaskTracker;
26use tokio_util::task::task_tracker::TaskTrackerToken;
27
28pub use avril_net::Address;
29use avril_net::{Endpoint, Listener};
30
31pub type Error = Box<dyn std::error::Error + Send + Sync>;
32type Body = UnsyncBoxBody<Bytes, Error>;
33type Requests = Arc<Mutex<HashMap<u64, Arc<Exchange>>>>;
34type Upload = mpsc::Sender<Result<Frame<Bytes>, Error>>;
35pub type Authorize = Arc<dyn Fn(&Address) -> Result<(), Error> + Send + Sync>;
36pub type Metadata = (u64, String, String, Vec<(String, String)>, bool, Endpoint);
37pub type RespondArgs = (u64, u16, Vec<(String, String)>, Option<Bytes>, bool);
38
39const MAX_ID: u64 = 9_007_199_254_740_991;
40
41enum BodyKind {
42    Inline(Bytes),
43    GuestStream,
44    File(Arc<file::FileBody>),
45}
46
47struct Exchange {
48    server: Weak<Server>,
49    method: hyper::Method,
50    version: hyper::Version,
51    headers: hyper::HeaderMap,
52    upgrade: Mutex<Option<hyper::upgrade::OnUpgrade>>,
53    pending_upgrade: Mutex<Option<PendingUpgrade>>,
54    body: AsyncMutex<Incoming>,
55    reply: Mutex<Option<oneshot::Sender<Response<Body>>>>,
56    upload: Mutex<Option<Upload>>,
57    done: CancellationToken,
58    disconnected: AtomicBool,
59}
60
61impl Exchange {
62    fn check(&self) -> Result<(), Error> {
63        self.server
64            .upgrade()
65            .ok_or("HTTP server is closed")?
66            .check()
67    }
68}
69
70struct Lifetime {
71    id: u64,
72    exchange: Arc<Exchange>,
73    requests: Requests,
74    complete: bool,
75}
76
77impl Drop for Lifetime {
78    fn drop(&mut self) {
79        self.exchange
80            .disconnected
81            .store(!self.complete, Ordering::Relaxed);
82        self.exchange.done.cancel();
83        self.exchange.upload.lock().unwrap().take();
84        self.exchange.pending_upgrade.lock().unwrap().take();
85        self.requests.lock().unwrap().remove(&self.id);
86    }
87}
88
89struct PendingUpgrade {
90    headers: hyper::HeaderMap,
91    ready: oneshot::Sender<Lifetime>,
92}
93
94pub struct Upgrade {
95    on_upgrade: hyper::upgrade::OnUpgrade,
96    ready: oneshot::Receiver<Lifetime>,
97    pub canceled: CancellationToken,
98    token: TaskTrackerToken,
99}
100
101pub struct Lease {
102    _lifetime: Lifetime,
103    _token: TaskTrackerToken,
104}
105
106impl Upgrade {
107    pub async fn accept(self) -> Result<(hyper::upgrade::Upgraded, Lease), Error> {
108        let lifetime = tokio::select! {
109            _ = self.canceled.cancelled() => return Err("HTTP server aborted".into()),
110            ready = self.ready => ready.map_err(|_| "WebSocket upgrade response was not returned")?,
111        };
112        let stream = tokio::select! {
113            _ = self.canceled.cancelled() => return Err("HTTP server aborted".into()),
114            stream = self.on_upgrade => stream?,
115        };
116        Ok((
117            stream,
118            Lease {
119                _lifetime: lifetime,
120                _token: self.token,
121            },
122        ))
123    }
124}
125
126struct ResponseBody {
127    inner: Body,
128    lifetime: Lifetime,
129    remaining: Option<u64>,
130    failed: bool,
131}
132
133impl HttpBody for ResponseBody {
134    type Data = Bytes;
135    type Error = Error;
136
137    fn poll_frame(
138        mut self: Pin<&mut Self>,
139        cx: &mut Context<'_>,
140    ) -> Poll<Option<Result<Frame<Bytes>, Error>>> {
141        let result = Pin::new(&mut self.inner).poll_frame(cx);
142        if let Poll::Ready(Some(frame)) = &result {
143            match frame {
144                Ok(frame) => {
145                    if let (Some(remaining), Some(bytes)) = (self.remaining, frame.data_ref()) {
146                        self.remaining = remaining.checked_sub(bytes.len() as u64);
147                        if self.remaining.is_none() {
148                            self.failed = true;
149                        }
150                    }
151                }
152                Err(_) => self.failed = true,
153            }
154        }
155        if (matches!(result, Poll::Ready(None)) || self.inner.is_end_stream())
156            && self.remaining.is_some_and(|remaining| remaining != 0)
157        {
158            self.failed = true;
159        }
160        if !self.failed
161            && (self.remaining == Some(0)
162                || matches!(result, Poll::Ready(None))
163                || self.inner.is_end_stream())
164        {
165            self.lifetime.complete = true;
166        }
167        result
168    }
169
170    fn is_end_stream(&self) -> bool {
171        self.inner.is_end_stream()
172    }
173    fn size_hint(&self) -> SizeHint {
174        self.inner.size_hint()
175    }
176}
177
178impl Drop for ResponseBody {
179    fn drop(&mut self) {
180        // Hyper can stop polling at Content-Length without ever observing EOF.
181        if !self.failed && (self.remaining == Some(0) || self.inner.is_end_stream()) {
182            self.lifetime.complete = true;
183        }
184    }
185}
186
187struct FileResponseBody {
188    file: Arc<file::FileBody>,
189    request: Arc<Exchange>,
190    pending: Option<BoxFuture<'static, Result<(Bytes, bool), Error>>>,
191    remaining: u64,
192    ended: bool,
193}
194
195impl HttpBody for FileResponseBody {
196    type Data = Bytes;
197    type Error = Error;
198
199    fn poll_frame(
200        mut self: Pin<&mut Self>,
201        cx: &mut Context<'_>,
202    ) -> Poll<Option<Result<Frame<Bytes>, Error>>> {
203        if self.ended {
204            return Poll::Ready(None);
205        }
206        if self.pending.is_none() {
207            let file = self.file.clone();
208            let request = self.request.clone();
209            self.pending = Some(Box::pin(async move {
210                request.check()?;
211                let result = tokio::select! {
212                    biased;
213                    _ = request.done.cancelled() => return Err("HTTP request canceled".into()),
214                    result = file.read() => result?,
215                };
216                request.check()?;
217                Ok((Bytes::from(result.0), result.1))
218            }));
219        }
220        match self.pending.as_mut().unwrap().as_mut().poll(cx) {
221            Poll::Pending => Poll::Pending,
222            Poll::Ready(result) => {
223                self.pending = None;
224                match result {
225                    Ok((bytes, done)) => {
226                        self.remaining -= bytes.len() as u64;
227                        self.ended = done;
228                        Poll::Ready(Some(Ok(Frame::data(bytes))))
229                    }
230                    Err(error) => {
231                        self.ended = true;
232                        self.file.close();
233                        Poll::Ready(Some(Err(error)))
234                    }
235                }
236            }
237        }
238    }
239
240    fn is_end_stream(&self) -> bool {
241        self.ended
242    }
243
244    fn size_hint(&self) -> SizeHint {
245        SizeHint::with_exact(self.remaining)
246    }
247}
248
249impl Drop for FileResponseBody {
250    fn drop(&mut self) {
251        self.file.close();
252    }
253}
254
255struct Server {
256    addr: Address,
257    authorize: Authorize,
258    upgrades: TaskTracker,
259    queue: mpsc::Sender<Metadata>,
260    incoming: AsyncMutex<mpsc::Receiver<Metadata>>,
261    stop: CancellationToken,
262    abort: CancellationToken,
263    done: CancellationToken,
264    error: Mutex<Option<String>>,
265    requests: Requests,
266    next: Arc<AtomicU64>,
267}
268
269impl Server {
270    fn check(&self) -> Result<(), Error> {
271        (self.authorize)(&self.addr)
272    }
273
274    async fn request(
275        self: Arc<Self>,
276        mut request: Request<Incoming>,
277        remote: Endpoint,
278    ) -> Result<Response<Body>, Error> {
279        self.check()?;
280        if request.method() == hyper::Method::CONNECT {
281            return Ok(Response::builder()
282                .status(StatusCode::NOT_IMPLEMENTED)
283                .body(
284                    Full::new(Bytes::new())
285                        .map_err(|never| match never {})
286                        .boxed_unsync(),
287                )?);
288        }
289        let authority = request
290            .headers()
291            .get("host")
292            .map(|value| value.to_str())
293            .transpose()?
294            .map(str::to_owned)
295            .unwrap_or_else(|| match &self.addr {
296                Address::Tcp { hostname, port } => {
297                    if hostname.contains(':') {
298                        format!("[{hostname}]:{port}")
299                    } else {
300                        format!("{hostname}:{port}")
301                    }
302                }
303                Address::Unix { .. } => "localhost".to_owned(),
304            });
305        authority.parse::<hyper::http::uri::Authority>()?;
306        let path = request
307            .uri()
308            .path_and_query()
309            .map_or("/", |path| path.as_str());
310        let path = if path == "*" { "/" } else { path };
311        let url = url::Url::parse(&format!("http://{authority}{path}"))?;
312        if !url.username().is_empty() || url.password().is_some() || url.host_str().is_none() {
313            return Err("Invalid HTTP request authority".into());
314        }
315        let id = self
316            .next
317            .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |id| {
318                (id <= MAX_ID).then_some(id + 1)
319            })
320            .map_err(|_| "HTTP request IDs exhausted")?;
321        let headers = request
322            .headers()
323            .iter()
324            .map(|(name, value)| {
325                (
326                    name.to_string(),
327                    value
328                        .as_bytes()
329                        .iter()
330                        .map(|byte| char::from(*byte))
331                        .collect(),
332                )
333            })
334            .collect();
335        let has_body = !request.body().is_end_stream();
336        let upgrade = hyper::upgrade::on(&mut request);
337        let original_headers = request.headers().clone();
338        let version = request.version();
339        let method = request.method().clone();
340        let (reply, receive) = oneshot::channel();
341        let exchange = Arc::new(Exchange {
342            server: Arc::downgrade(&self),
343            method: method.clone(),
344            version,
345            headers: original_headers,
346            upgrade: Mutex::new(Some(upgrade)),
347            pending_upgrade: Mutex::new(None),
348            body: AsyncMutex::new(request.into_body()),
349            reply: Mutex::new(Some(reply)),
350            upload: Mutex::new(None),
351            done: CancellationToken::new(),
352            disconnected: AtomicBool::new(false),
353        });
354        self.requests.lock().unwrap().insert(id, exchange.clone());
355        let lifetime = Lifetime {
356            id,
357            exchange: exchange.clone(),
358            requests: self.requests.clone(),
359            complete: false,
360        };
361        tokio::select! {
362            biased;
363            _ = self.stop.cancelled() => return Err("HTTP server is shutting down".into()),
364            result = self.queue.send((id, method.to_string(), url.into(), headers, has_body, remote)) => {
365                result.map_err(|_| "HTTP dispatcher stopped")?;
366            }
367        }
368        let response = tokio::select! {
369            _ = exchange.done.cancelled() => return Err("HTTP request canceled".into()),
370            response = receive => response.map_err(|_| "HTTP handler stopped")?,
371        };
372        if response.status() == StatusCode::SWITCHING_PROTOCOLS {
373            let pending = exchange
374                .pending_upgrade
375                .lock()
376                .unwrap()
377                .take()
378                .ok_or("WebSocket upgrade was not prepared")?;
379            pending
380                .ready
381                .send(lifetime)
382                .map_err(|_| "WebSocket upgrade was canceled")?;
383            return Ok(response);
384        }
385        exchange.pending_upgrade.lock().unwrap().take();
386        let suppressed = exchange.method == hyper::Method::HEAD
387            || matches!(response.status().as_u16(), 204 | 205 | 304);
388        let remaining = if suppressed {
389            Some(0)
390        } else {
391            response
392                .headers()
393                .get("content-length")
394                .and_then(|value| value.to_str().ok()?.parse().ok())
395        };
396        let (parts, inner) = response.into_parts();
397        Ok(Response::from_parts(
398            parts,
399            ResponseBody {
400                inner,
401                lifetime,
402                remaining,
403                failed: false,
404            }
405            .boxed_unsync(),
406        ))
407    }
408
409    async fn serve(self: Arc<Self>, listener: Listener) -> Result<(), Error> {
410        let mut connections = JoinSet::new();
411        loop {
412            tokio::select! {
413                biased;
414                _ = self.stop.cancelled() => break,
415                Some(_) = connections.join_next(), if !connections.is_empty() => {},
416                accepted = listener.accept() => {
417                    let avril_net::Accepted { socket, remote, .. } = match accepted {
418                        Ok(accepted) => accepted,
419                        Err(error) => {
420                            if matches!(error.kind(), io::ErrorKind::ConnectionAborted | io::ErrorKind::ConnectionReset | io::ErrorKind::Interrupted) {
421                                continue;
422                            }
423                            let exhausted = error.kind() == io::ErrorKind::OutOfMemory;
424                            #[cfg(unix)]
425                            let exhausted = exhausted || matches!(error.raw_os_error(), Some(libc::EMFILE | libc::ENFILE | libc::ENOBUFS | libc::ENOMEM));
426                            #[cfg(windows)]
427                            let exhausted = exhausted || matches!(error.raw_os_error(), Some(10024 | 10055));
428                            if !exhausted {
429                                return Err(error.into());
430                            }
431                            tokio::select! {
432                                _ = self.stop.cancelled() => break,
433                                _ = tokio::time::sleep(std::time::Duration::from_millis(100)) => {},
434                            }
435                            continue;
436                        }
437                    };
438                    self.check()?;
439                    let server = self.clone();
440                    connections.spawn(async move {
441                        let service_server = server.clone();
442                        let connection = http1::Builder::new().timer(TokioTimer::new()).serve_connection(TokioIo::new(socket), service_fn(move |request| {
443                            service_server.clone().request(request, remote.clone())
444                        })).with_upgrades();
445                        tokio::pin!(connection);
446                        tokio::select! {
447                            biased;
448                            _ = server.abort.cancelled() => {},
449                            _ = server.stop.cancelled() => {
450                                connection.as_mut().graceful_shutdown();
451                                tokio::select! {
452                                    _ = server.abort.cancelled() => {},
453                                    _ = &mut connection => {},
454                                }
455                            },
456                            _ = &mut connection => {},
457                        }
458                    });
459                }
460            }
461        }
462        drop(listener);
463        while connections.join_next().await.is_some() {}
464        self.upgrades.close();
465        self.upgrades.wait().await;
466        Ok(())
467    }
468}
469
470pub struct Engine {
471    runtime: tokio::runtime::Handle,
472    servers: Mutex<HashMap<u64, Arc<Server>>>,
473    requests: Requests,
474    next_server: AtomicU64,
475    next_request: Arc<AtomicU64>,
476}
477
478impl Drop for Engine {
479    fn drop(&mut self) {
480        for server in self.servers.get_mut().unwrap().values() {
481            server.stop.cancel();
482            server.abort.cancel();
483        }
484    }
485}
486
487impl Engine {
488    fn server(&self, id: u64) -> Result<Arc<Server>, Error> {
489        self.servers
490            .lock()
491            .unwrap()
492            .get(&id)
493            .cloned()
494            .ok_or_else(|| "HTTP server is closed".into())
495    }
496
497    fn request(&self, id: u64) -> Result<Arc<Exchange>, Error> {
498        self.requests
499            .lock()
500            .unwrap()
501            .get(&id)
502            .cloned()
503            .ok_or_else(|| "HTTP request is closed".into())
504    }
505
506    fn run<T: Send + 'static, F: Future<Output = Result<T, Error>> + Send + 'static>(
507        &self,
508        future: F,
509    ) -> impl Future<Output = Result<T, io::Error>> + use<T, F> {
510        let handle = self.runtime.spawn(future);
511        async move {
512            // Dropping the handle detaches the task rather than aborting it.
513            handle
514                .await
515                .map_err(|_| io::Error::other("HTTP worker stopped"))?
516                .map_err(io::Error::other)
517        }
518    }
519
520    pub fn upgrade(
521        &self,
522        id: u64,
523        protocol: Option<&str>,
524    ) -> Result<(Upgrade, Vec<(String, String)>), Error> {
525        let request = self.request(id)?;
526        request.check()?;
527        let token = |name, token: &str| {
528            request.headers.get_all(name).iter().any(|value| {
529                value.to_str().is_ok_and(|value| {
530                    value
531                        .split(',')
532                        .any(|value| value.trim().eq_ignore_ascii_case(token))
533                })
534            })
535        };
536        let single = |name| {
537            let mut values = request.headers.get_all(name).iter();
538            let value = values
539                .next()
540                .ok_or("Missing WebSocket handshake header")?
541                .to_str()?;
542            if values.next().is_some() {
543                return Err("Duplicate WebSocket handshake header".into());
544            }
545            Ok::<_, Error>(value)
546        };
547        if request.method != hyper::Method::GET
548            || request.version != hyper::Version::HTTP_11
549            || !token("connection", "upgrade")
550            || !token("upgrade", "websocket")
551            || single("sec-websocket-version")? != "13"
552        {
553            return Err("Invalid WebSocket upgrade request".into());
554        }
555        let key = single("sec-websocket-key")?;
556        if base64::engine::general_purpose::STANDARD.decode(key)?.len() != 16 {
557            return Err("Invalid WebSocket key".into());
558        }
559        if let Some(protocol) = protocol
560            && (protocol.is_empty()
561                || !protocol
562                    .bytes()
563                    .all(|byte| byte.is_ascii_alphanumeric() || b"!#$%&'*+-.^_`|~".contains(&byte))
564                || !request
565                    .headers
566                    .get_all("sec-websocket-protocol")
567                    .iter()
568                    .any(|value| {
569                        value.to_str().is_ok_and(|value| {
570                            value.split(',').any(|value| value.trim() == protocol)
571                        })
572                    }))
573        {
574            return Err("WebSocket protocol was not offered by the client".into());
575        }
576        let mut hash = sha1::Sha1::new();
577        hash.update(key.as_bytes());
578        hash.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
579        let mut response = Response::builder()
580            .status(101)
581            .header("connection", "Upgrade")
582            .header("upgrade", "websocket")
583            .header(
584                "sec-websocket-accept",
585                base64::engine::general_purpose::STANDARD.encode(hash.finalize()),
586            );
587        if let Some(protocol) = protocol {
588            response = response.header("sec-websocket-protocol", protocol);
589        }
590        let response = response.body(())?;
591        let headers = response
592            .headers()
593            .iter()
594            .map(|(name, value)| (name.to_string(), value.to_str().unwrap().to_owned()))
595            .collect();
596        let server = request.server.upgrade().ok_or("HTTP server is closed")?;
597        let on_upgrade = request
598            .upgrade
599            .lock()
600            .unwrap()
601            .take()
602            .ok_or("WebSocket upgrade already prepared")?;
603        let (ready, receive) = oneshot::channel();
604        *request.pending_upgrade.lock().unwrap() = Some(PendingUpgrade {
605            headers: response.into_parts().0.headers,
606            ready,
607        });
608        Ok((
609            Upgrade {
610                on_upgrade,
611                ready: receive,
612                canceled: server.abort.clone(),
613                token: server.upgrades.token(),
614            },
615            headers,
616        ))
617    }
618
619    pub fn next(
620        &self,
621        id: u64,
622    ) -> impl Future<Output = Result<Option<Metadata>, io::Error>> + use<> {
623        let server = self.server(id);
624        self.run(async move {
625            let server = server?;
626            tokio::select! {
627                biased;
628                _ = server.stop.cancelled() => Ok(server.incoming.lock().await.try_recv().ok()),
629                item = async { server.incoming.lock().await.recv().await } => Ok(item),
630            }
631        })
632    }
633
634    pub fn finished(
635        self: &Arc<Self>,
636        id: u64,
637    ) -> impl Future<Output = Result<(), io::Error>> + use<> {
638        let server = self.server(id);
639        let pending = self.run(async move {
640            let server = server?;
641            server.done.cancelled().await;
642            let error = server.error.lock().unwrap().clone();
643            if let Some(error) = error {
644                Err(error.into())
645            } else {
646                Ok(())
647            }
648        });
649        let engine = self.clone();
650        async move {
651            let result = pending.await;
652            engine.servers.lock().unwrap().remove(&id);
653            result
654        }
655    }
656
657    pub fn stop_all(&self, force: bool) {
658        for server in self.servers.lock().unwrap().values() {
659            server.stop.cancel();
660            if force {
661                server.abort.cancel();
662            }
663        }
664    }
665
666    pub fn stop(&self, id: u64, force: bool) {
667        if let Ok(server) = self.server(id) {
668            server.stop.cancel();
669            if force {
670                server.abort.cancel();
671            }
672        }
673    }
674
675    pub fn read(&self, id: u64) -> impl Future<Output = Result<Option<Bytes>, io::Error>> + use<> {
676        let request = self.request(id);
677        self.run(async move {
678            let request = request?;
679            request.check()?;
680            tokio::select! {
681                _ = request.done.cancelled() => Err("HTTP request canceled".into()),
682                result = async {
683                    let mut body = request.body.lock().await;
684                    while let Some(frame) = body.frame().await {
685                        if let Ok(data) = frame?.into_data() { return Ok(Some(data)); }
686                    }
687                    Ok(None)
688                } => result,
689            }
690        })
691    }
692
693    pub fn write(
694        &self,
695        id: u64,
696        bytes: Option<Bytes>,
697    ) -> impl Future<Output = Result<bool, io::Error>> + use<> {
698        let request = self.request(id);
699        self.run(async move {
700            let Ok(request) = request else {
701                return Ok(false);
702            };
703            request.check()?;
704            if let Some(bytes) = bytes {
705                let Some(upload) = request.upload.lock().unwrap().clone() else {
706                    return Ok(false);
707                };
708                tokio::select! {
709                    _ = request.done.cancelled() => Ok(false),
710                    result = upload.send(Ok(Frame::data(bytes))) => Ok(result.is_ok()),
711                }
712            } else {
713                Ok(request.upload.lock().unwrap().take().is_some())
714            }
715        })
716    }
717
718    pub fn wait(&self, id: u64) -> impl Future<Output = Result<bool, io::Error>> + use<> {
719        let request = self.request(id);
720        self.run(async move {
721            let request = request?;
722            request.done.cancelled().await;
723            Ok(request.disconnected.load(Ordering::Relaxed))
724        })
725    }
726
727    pub fn cancel(&self, id: u64) {
728        if let Ok(request) = self.request(id) {
729            request.disconnected.store(true, Ordering::Relaxed);
730            request.done.cancel();
731            request.pending_upgrade.lock().unwrap().take();
732        }
733    }
734
735    pub fn new(runtime: tokio::runtime::Handle) -> Self {
736        Self {
737            runtime,
738            servers: Mutex::new(HashMap::new()),
739            requests: Arc::new(Mutex::new(HashMap::new())),
740            next_server: AtomicU64::new(1),
741            next_request: Arc::new(AtomicU64::new(1)),
742        }
743    }
744
745    pub fn listen(&self, address: Address, authorize: Authorize) -> Result<(u64, Address), Error> {
746        authorize(&address)?;
747        let (listener, addr) = Listener::bind(&self.runtime, &address)?;
748        let addr = Address::from(addr);
749        authorize(&addr)?;
750        let id = self
751            .next_server
752            .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |id| {
753                (id <= MAX_ID).then_some(id + 1)
754            })
755            .map_err(|_| "HTTP server IDs exhausted")?;
756        let (queue, incoming) = mpsc::channel(64);
757        let server = Arc::new(Server {
758            addr: addr.clone(),
759            authorize,
760            upgrades: TaskTracker::new(),
761            queue,
762            incoming: AsyncMutex::new(incoming),
763            stop: CancellationToken::new(),
764            abort: CancellationToken::new(),
765            done: CancellationToken::new(),
766            error: Mutex::new(None),
767            requests: self.requests.clone(),
768            next: self.next_request.clone(),
769        });
770        self.servers.lock().unwrap().insert(id, server.clone());
771        self.runtime.spawn(async move {
772            if let Err(error) = server.clone().serve(listener).await {
773                *server.error.lock().unwrap() = Some(error.to_string());
774                server.abort.cancel();
775                server.upgrades.close();
776                server.upgrades.wait().await;
777            }
778            server.stop.cancel();
779            server.done.cancel();
780        });
781        Ok((id, addr))
782    }
783
784    pub fn respond(&self, args: RespondArgs) -> Result<bool, Error> {
785        let (id, status, headers, bytes, streaming) = args;
786        let body = if streaming {
787            BodyKind::GuestStream
788        } else {
789            BodyKind::Inline(bytes.unwrap_or_default())
790        };
791        self.respond_inner(id, status, headers, body)
792    }
793
794    pub fn respond_file(
795        &self,
796        id: u64,
797        status: u16,
798        headers: Vec<(String, String)>,
799        file: Arc<file::FileBody>,
800    ) -> Result<bool, Error> {
801        self.respond_inner(id, status, headers, BodyKind::File(file))
802    }
803
804    fn respond_inner(
805        &self,
806        id: u64,
807        status: u16,
808        headers: Vec<(String, String)>,
809        body: BodyKind,
810    ) -> Result<bool, Error> {
811        let request = self.request(id)?;
812        request.check()?;
813        if status == 101 {
814            let mut response = Response::new(
815                Full::new(Bytes::new())
816                    .map_err(|never| match never {})
817                    .boxed_unsync(),
818            );
819            *response.status_mut() = StatusCode::SWITCHING_PROTOCOLS;
820            *response.headers_mut() = request
821                .pending_upgrade
822                .lock()
823                .unwrap()
824                .as_ref()
825                .ok_or("WebSocket upgrade was not prepared")?
826                .headers
827                .clone();
828            request
829                .reply
830                .lock()
831                .unwrap()
832                .take()
833                .ok_or("HTTP request already answered")?
834                .send(response)
835                .map_err(|_| "HTTP client disconnected")?;
836            return Ok(false);
837        }
838        if !(200..=599).contains(&status) {
839            return Err("Invalid HTTP response status".into());
840        }
841        let mut response = Response::builder().status(status);
842        for (name, value) in headers {
843            if [
844                "connection",
845                "transfer-encoding",
846                "upgrade",
847                "trailer",
848                "keep-alive",
849                "proxy-connection",
850            ]
851            .contains(&name.to_ascii_lowercase().as_str())
852            {
853                return Err(format!("Unsupported HTTP response header: {name}").into());
854            }
855            let value = value
856                .chars()
857                .map(|c| u8::try_from(c as u32))
858                .collect::<Result<Vec<_>, _>>()?;
859            response = response.header(name, value);
860        }
861        let suppressed = request.method == hyper::Method::HEAD || matches!(status, 204 | 205 | 304);
862        if !matches!(body, BodyKind::GuestStream)
863            && !matches!(status, 204 | 304)
864            && !response
865                .headers_ref()
866                .is_some_and(|headers| headers.contains_key("content-length"))
867        {
868            response = response.header(
869                "content-length",
870                if status == 205 {
871                    0
872                } else {
873                    match &body {
874                        BodyKind::Inline(bytes) => bytes.len() as u64,
875                        BodyKind::File(file) => file.len(),
876                        BodyKind::GuestStream => 0,
877                    }
878                },
879            );
880        }
881        if let Some(length) = response
882            .headers_ref()
883            .and_then(|headers| headers.get("content-length"))
884        {
885            let length = length.to_str()?;
886            if length.is_empty() || !length.bytes().all(|byte| byte.is_ascii_digit()) {
887                return Err("Invalid response Content-Length".into());
888            }
889            let length = length.parse::<u64>()?;
890            let mismatch = match &body {
891                BodyKind::Inline(bytes) => !suppressed && length != bytes.len() as u64,
892                BodyKind::File(file) => !suppressed && length != file.len(),
893                BodyKind::GuestStream => false,
894            };
895            if status == 204 || (status == 205 && length != 0) || mismatch {
896                return Err("Response Content-Length does not match the body".into());
897            }
898        }
899        let guest_streaming = matches!(body, BodyKind::GuestStream) && !suppressed;
900        let body = match body {
901            BodyKind::File(file) if !suppressed => FileResponseBody {
902                remaining: file.len(),
903                file,
904                request: request.clone(),
905                pending: None,
906                ended: false,
907            }
908            .boxed_unsync(),
909            BodyKind::GuestStream if !suppressed => {
910                let (send, receive) = mpsc::channel(1);
911                *request.upload.lock().unwrap() = Some(send);
912                let done = request.done.clone();
913                let stream = futures::stream::unfold(
914                    (receive, done, false),
915                    |(mut receive, done, ended)| async move {
916                        if ended {
917                            return None;
918                        }
919                        tokio::select! {
920                            biased;
921                            _ = done.cancelled() => Some((Err("HTTP request canceled".into()), (receive, done, true))),
922                            frame = receive.recv() => frame.map(|frame| (frame, (receive, done, false))),
923                        }
924                    },
925                );
926                StreamBody::new(stream).boxed_unsync()
927            }
928            BodyKind::Inline(bytes) => Full::new(if suppressed { Bytes::new() } else { bytes })
929                .map_err(|never| match never {})
930                .boxed_unsync(),
931            BodyKind::File(_) | BodyKind::GuestStream => Full::new(Bytes::new())
932                .map_err(|never| match never {})
933                .boxed_unsync(),
934        };
935        let response = response.body(body)?;
936        request
937            .reply
938            .lock()
939            .unwrap()
940            .take()
941            .ok_or("HTTP request already answered")?
942            .send(response)
943            .map_err(|_| "HTTP client disconnected")?;
944        Ok(guest_streaming)
945    }
946}