Skip to main content

esp_idf_svc/http/
server.rs

1//! HTTP server
2//!
3//! Provides an HTTP(S) server in `EspHttpServer`, plus all related structs.
4//!
5//! Typical usage of `EspHttpServer` involves creating a function (or closure)
6//! for every URI+method that the server is meant to handle. A minimal server that
7//! only handles HTTP GET requests to `index.html` looks like this:
8//!
9//! ```
10//! use esp_idf_svc::http::server::{Configuration, EspHttpServer};
11//!
12//! let mut server = EspHttpServer::new(&Configuration::default())?;
13//!
14//! server.fn_handler("/index.html", Method::Get, |request| {
15//!     request
16//!         .into_ok_response()?
17//!         .write_all(b"<html><body>Hello world!</body></html>")
18//! })?;
19//! ```
20//!
21//! Note that the server is automatically started when instantiated, and stopped
22//! when dropped. If you want to keep the server running indefinitely then
23//! make sure it's not dropped - you may add an infinite loop after the server
24//! is created, use `core::mem::forget`, or keep around a reference to it somehow.
25//!
26//! You can find an example of handling GET/POST requests at [`examples/http_server.rs`](https://github.com/esp-rs/esp-idf-svc/blob/master/examples/http_server.rs).
27//!
28//! You can find an example of HTTP+Websockets at [`examples/http_ws_server.rs`](https://github.com/esp-rs/esp-idf-svc/blob/master/examples/http_ws_server.rs).
29//!
30//! By default, the ESP-IDF library allocates 512 bytes for reading and parsing
31//! HTTP headers, but desktop web browsers might send headers longer than that.
32//! If this becomes a problem, add `CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024` to your
33//! `sdkconfig.defaults` file.
34
35use core::cell::UnsafeCell;
36use core::fmt::Debug;
37use core::marker::PhantomData;
38#[cfg(esp_idf_lwip_ipv4)]
39use core::net::Ipv4Addr;
40#[cfg(esp_idf_lwip_ipv6)]
41use core::net::Ipv6Addr;
42use core::sync::atomic::{AtomicBool, Ordering};
43use core::time::*;
44use core::{ffi, ptr};
45
46extern crate alloc;
47use alloc::borrow::ToOwned;
48use alloc::boxed::Box;
49use alloc::collections::BTreeMap;
50use alloc::string::String;
51use alloc::string::ToString;
52use alloc::sync::Arc;
53use alloc::vec::Vec;
54
55use ::log::{info, warn};
56
57use embedded_svc::http::headers::content_type;
58use embedded_svc::io::{ErrorType, Read, Write};
59
60use esp_idf_hal::cpu::Core;
61
62use crate::sys::*;
63
64use uncased::{Uncased, UncasedStr};
65
66use crate::handle::RawHandle;
67use crate::io::EspIOError;
68use crate::private::common::Newtype;
69use crate::private::cstr::to_cstring_arg;
70use crate::private::cstr::{CStr, CString};
71use crate::private::mutex::Mutex;
72#[cfg(esp_idf_esp_https_server_enable)]
73use crate::tls::X509;
74
75pub use embedded_svc::http::server::{
76    CompositeHandler, Connection, FnHandler, Handler, Middleware, Request, Response,
77};
78pub use embedded_svc::utils::http::server::registration::*;
79
80pub use super::*;
81
82#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
83pub struct KeepAlive {
84    pub idle_secs: u32,
85    pub interval_secs: u32,
86    pub probe_count: u32,
87}
88
89impl KeepAlive {
90    pub const fn new() -> Self {
91        Self {
92            idle_secs: 5,
93            interval_secs: 5,
94            probe_count: 3,
95        }
96    }
97}
98
99impl Default for KeepAlive {
100    fn default() -> Self {
101        Self::new()
102    }
103}
104
105#[derive(Copy, Clone, Debug)]
106pub struct Configuration {
107    pub http_port: u16,
108    pub ctrl_port: u16,
109    pub https_port: u16,
110    pub core: Option<Core>,
111    pub max_sessions: usize,
112    pub session_timeout: Duration,
113    pub task_caps: u32,
114    pub stack_size: usize,
115    pub max_open_sockets: usize,
116    pub max_uri_handlers: usize,
117    pub max_resp_headers: usize,
118    pub lru_purge_enable: bool,
119    pub uri_match_wildcard: bool,
120    pub keep_alive: Option<KeepAlive>,
121    pub so_linger: Option<Duration>,
122    #[cfg(esp_idf_esp_https_server_enable)]
123    pub server_certificate: Option<X509<'static>>,
124    #[cfg(esp_idf_esp_https_server_enable)]
125    pub private_key: Option<X509<'static>>,
126}
127
128impl Default for Configuration {
129    fn default() -> Self {
130        Configuration {
131            http_port: 80,
132            ctrl_port: 32768,
133            https_port: 443,
134            core: None,
135            max_sessions: 16,
136            session_timeout: Duration::from_secs(20 * 60),
137            task_caps: (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT),
138            #[cfg(not(esp_idf_esp_https_server_enable))]
139            stack_size: 6144,
140            #[cfg(esp_idf_esp_https_server_enable)]
141            stack_size: 10240,
142            max_open_sockets: 4,
143            max_uri_handlers: 32,
144            max_resp_headers: 8,
145            lru_purge_enable: true,
146            uri_match_wildcard: false,
147            keep_alive: None,
148            so_linger: None,
149            #[cfg(esp_idf_esp_https_server_enable)]
150            server_certificate: None,
151            #[cfg(esp_idf_esp_https_server_enable)]
152            private_key: None,
153        }
154    }
155}
156
157impl From<&Configuration> for Newtype<httpd_config_t> {
158    #[allow(clippy::needless_update)]
159    fn from(conf: &Configuration) -> Self {
160        Self(httpd_config_t {
161            task_priority: 5,
162            // Since 5.3.0
163            #[cfg(any(
164                all(not(esp_idf_version_major = "4"), not(esp_idf_version_major = "5")),
165                all(
166                    esp_idf_version_major = "5",
167                    not(any(
168                        esp_idf_version_minor = "0",
169                        esp_idf_version_minor = "1",
170                        esp_idf_version_minor = "2"
171                    ))
172                ),
173            ))]
174            task_caps: conf.task_caps,
175            stack_size: conf.stack_size,
176            core_id: conf.core.map(|core| core.into()).unwrap_or(i32::MAX),
177            server_port: conf.http_port,
178            ctrl_port: conf.ctrl_port,
179            max_open_sockets: conf.max_open_sockets as _,
180            max_uri_handlers: conf.max_uri_handlers as _,
181            max_resp_headers: conf.max_resp_headers as _,
182            backlog_conn: 5,
183            lru_purge_enable: conf.lru_purge_enable,
184            recv_wait_timeout: 5,
185            send_wait_timeout: 5,
186            global_user_ctx: ptr::null_mut(),
187            global_user_ctx_free_fn: None,
188            global_transport_ctx: ptr::null_mut(),
189            global_transport_ctx_free_fn: None,
190            open_fn: None,
191            close_fn: None,
192            uri_match_fn: conf.uri_match_wildcard.then_some(httpd_uri_match_wildcard),
193            keep_alive_enable: conf.keep_alive.is_some(),
194            keep_alive_idle: conf.keep_alive.map(|ka| ka.idle_secs as i32).unwrap_or(0),
195            keep_alive_interval: conf
196                .keep_alive
197                .map(|ka| ka.interval_secs as i32)
198                .unwrap_or(0),
199            keep_alive_count: conf.keep_alive.map(|ka| ka.probe_count as i32).unwrap_or(0),
200            enable_so_linger: conf.so_linger.is_some(),
201            linger_timeout: conf.so_linger.map(|d| d.as_secs() as i32).unwrap_or(0),
202            ..Default::default()
203        })
204    }
205}
206
207#[allow(non_upper_case_globals)]
208impl From<Newtype<ffi::c_uint>> for Method {
209    fn from(method: Newtype<ffi::c_uint>) -> Self {
210        match method.0 {
211            http_method_HTTP_GET => Method::Get,
212            http_method_HTTP_POST => Method::Post,
213            http_method_HTTP_DELETE => Method::Delete,
214            http_method_HTTP_HEAD => Method::Head,
215            http_method_HTTP_PUT => Method::Put,
216            http_method_HTTP_CONNECT => Method::Connect,
217            http_method_HTTP_OPTIONS => Method::Options,
218            http_method_HTTP_TRACE => Method::Trace,
219            http_method_HTTP_COPY => Method::Copy,
220            http_method_HTTP_LOCK => Method::Lock,
221            http_method_HTTP_MKCOL => Method::MkCol,
222            http_method_HTTP_MOVE => Method::Move,
223            http_method_HTTP_PROPFIND => Method::Propfind,
224            http_method_HTTP_PROPPATCH => Method::Proppatch,
225            http_method_HTTP_SEARCH => Method::Search,
226            http_method_HTTP_UNLOCK => Method::Unlock,
227            http_method_HTTP_BIND => Method::Bind,
228            http_method_HTTP_REBIND => Method::Rebind,
229            http_method_HTTP_UNBIND => Method::Unbind,
230            http_method_HTTP_ACL => Method::Acl,
231            http_method_HTTP_REPORT => Method::Report,
232            http_method_HTTP_MKACTIVITY => Method::MkActivity,
233            http_method_HTTP_CHECKOUT => Method::Checkout,
234            http_method_HTTP_MERGE => Method::Merge,
235            http_method_HTTP_MSEARCH => Method::MSearch,
236            http_method_HTTP_NOTIFY => Method::Notify,
237            http_method_HTTP_SUBSCRIBE => Method::Subscribe,
238            http_method_HTTP_UNSUBSCRIBE => Method::Unsubscribe,
239            http_method_HTTP_PATCH => Method::Patch,
240            http_method_HTTP_PURGE => Method::Purge,
241            http_method_HTTP_MKCALENDAR => Method::MkCalendar,
242            http_method_HTTP_LINK => Method::Link,
243            http_method_HTTP_UNLINK => Method::Unlink,
244            _ => unreachable!(),
245        }
246    }
247}
248
249#[cfg(esp_idf_esp_https_server_enable)]
250impl From<&Configuration> for Newtype<httpd_ssl_config_t> {
251    fn from(conf: &Configuration) -> Self {
252        let http_config: Newtype<httpd_config_t> = conf.into();
253        // start in insecure mode if no certificates are set
254        let transport_mode = match (conf.server_certificate, conf.private_key) {
255            (Some(_), Some(_)) => httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_SECURE,
256            _ => {
257                warn!("Starting server in insecure mode because no certificates were set in the http config.");
258                httpd_ssl_transport_mode_t_HTTPD_SSL_TRANSPORT_INSECURE
259            }
260        };
261        // Default values taken from: https://github.com/espressif/esp-idf/blob/master/components/esp_https_server/include/esp_https_server.h#L114
262
263        #[allow(clippy::needless_update)]
264        Self(httpd_ssl_config_t {
265            httpd: http_config.0,
266            session_tickets: false,
267            #[cfg(not(esp_idf_version_major = "4"))]
268            use_secure_element: false,
269            port_secure: conf.https_port,
270            port_insecure: conf.http_port,
271            transport_mode,
272            cacert_pem: ptr::null(),
273            cacert_len: 0,
274            prvtkey_pem: ptr::null(),
275            prvtkey_len: 0,
276            #[cfg(esp_idf_version_major = "4")]
277            client_verify_cert_pem: ptr::null(),
278            #[cfg(esp_idf_version_major = "4")]
279            client_verify_cert_len: 0,
280            #[cfg(not(esp_idf_version_major = "4"))]
281            servercert: ptr::null(),
282            #[cfg(not(esp_idf_version_major = "4"))]
283            servercert_len: 0,
284            user_cb: None,
285            ..Default::default()
286        })
287    }
288}
289
290impl From<Method> for Newtype<ffi::c_uint> {
291    fn from(method: Method) -> Self {
292        Self(match method {
293            Method::Get => http_method_HTTP_GET,
294            Method::Post => http_method_HTTP_POST,
295            Method::Delete => http_method_HTTP_DELETE,
296            Method::Head => http_method_HTTP_HEAD,
297            Method::Put => http_method_HTTP_PUT,
298            Method::Connect => http_method_HTTP_CONNECT,
299            Method::Options => http_method_HTTP_OPTIONS,
300            Method::Trace => http_method_HTTP_TRACE,
301            Method::Copy => http_method_HTTP_COPY,
302            Method::Lock => http_method_HTTP_LOCK,
303            Method::MkCol => http_method_HTTP_MKCOL,
304            Method::Move => http_method_HTTP_MOVE,
305            Method::Propfind => http_method_HTTP_PROPFIND,
306            Method::Proppatch => http_method_HTTP_PROPPATCH,
307            Method::Search => http_method_HTTP_SEARCH,
308            Method::Unlock => http_method_HTTP_UNLOCK,
309            Method::Bind => http_method_HTTP_BIND,
310            Method::Rebind => http_method_HTTP_REBIND,
311            Method::Unbind => http_method_HTTP_UNBIND,
312            Method::Acl => http_method_HTTP_ACL,
313            Method::Report => http_method_HTTP_REPORT,
314            Method::MkActivity => http_method_HTTP_MKACTIVITY,
315            Method::Checkout => http_method_HTTP_CHECKOUT,
316            Method::Merge => http_method_HTTP_MERGE,
317            Method::MSearch => http_method_HTTP_MSEARCH,
318            Method::Notify => http_method_HTTP_NOTIFY,
319            Method::Subscribe => http_method_HTTP_SUBSCRIBE,
320            Method::Unsubscribe => http_method_HTTP_UNSUBSCRIBE,
321            Method::Patch => http_method_HTTP_PATCH,
322            Method::Purge => http_method_HTTP_PURGE,
323            Method::MkCalendar => http_method_HTTP_MKCALENDAR,
324            Method::Link => http_method_HTTP_LINK,
325            Method::Unlink => http_method_HTTP_UNLINK,
326        })
327    }
328}
329
330static OPEN_SESSIONS: Mutex<BTreeMap<(u32, ffi::c_int), Arc<AtomicBool>>> =
331    Mutex::new(BTreeMap::new());
332static CLOSE_HANDLERS: Mutex<BTreeMap<u32, Vec<CloseHandler<'static>>>> =
333    Mutex::new(BTreeMap::new());
334
335type NativeHandler<'a> = Box<dyn Fn(*mut httpd_req_t) -> ffi::c_int + 'a>;
336type CloseHandler<'a> = Box<dyn Fn(ffi::c_int) + Send + 'a>;
337
338pub struct EspHttpServer<'a> {
339    sd: httpd_handle_t,
340    registrations: Vec<(CString, crate::sys::httpd_uri_t)>,
341    _reg: PhantomData<&'a ()>,
342}
343
344impl EspHttpServer<'static> {
345    pub fn new(conf: &Configuration) -> Result<Self, EspIOError> {
346        Self::internal_new(conf)
347    }
348}
349
350/// HTTP server
351impl<'a> EspHttpServer<'a> {
352    /// # Safety
353    ///
354    /// This method - in contrast to method `new` - allows the user to set
355    /// non-static callbacks/closures as handlers into the returned `EspHttpServer` service. This enables users to borrow
356    /// - in the closure - variables that live on the stack - or more generally - in the same
357    ///   scope where the service is created.
358    ///
359    /// HOWEVER: care should be taken NOT to call `core::mem::forget()` on the service,
360    /// as that would immediately lead to an UB (crash).
361    /// Also note that forgetting the service might happen with `Rc` and `Arc`
362    /// when circular references are introduced: <https://github.com/rust-lang/rust/issues/24456>
363    ///
364    /// The reason is that the closure is actually sent to a hidden ESP IDF thread.
365    /// This means that if the service is forgotten, Rust is free to e.g. unwind the stack
366    /// and the closure now owned by this other thread will end up with references to variables that no longer exist.
367    ///
368    /// The destructor of the service takes care - prior to the service being dropped and e.g.
369    /// the stack being unwind - to remove the closure from the hidden thread and destroy it.
370    /// Unfortunately, when the service is forgotten, the un-subscription does not happen
371    /// and invalid references are left dangling.
372    ///
373    /// This "local borrowing" will only be possible to express in a safe way once/if `!Leak` types
374    /// are introduced to Rust (i.e. the impossibility to "forget" a type and thus not call its destructor).
375    pub unsafe fn new_nonstatic(conf: &Configuration) -> Result<Self, EspIOError> {
376        Self::internal_new(conf)
377    }
378
379    fn internal_new(conf: &Configuration) -> Result<Self, EspIOError> {
380        let mut handle: httpd_handle_t = ptr::null_mut();
381        let handle_ref = &mut handle;
382
383        #[cfg(not(esp_idf_esp_https_server_enable))]
384        {
385            let mut config: Newtype<httpd_config_t> = conf.into();
386            config.0.close_fn = Some(Self::close_fn);
387            esp!(unsafe { httpd_start(handle_ref, &config.0 as *const _) })?;
388        }
389
390        #[cfg(esp_idf_esp_https_server_enable)]
391        {
392            let mut config: Newtype<httpd_ssl_config_t> = conf.into();
393            config.0.httpd.close_fn = Some(Self::close_fn);
394
395            if let (Some(cert), Some(private_key)) = (conf.server_certificate, conf.private_key) {
396                // NOTE: Contrary to other components in ESP IDF (HTTP & MQTT client),
397                // HTTP server does allocate internal buffers for the certificates
398                // Moreover - due to internal implementation details - it needs the
399                // full length of the certificate, even for the PEM case
400
401                #[cfg(esp_idf_version_major = "4")]
402                {
403                    config.0.cacert_pem = cert.as_esp_idf_raw_ptr() as _;
404                    config.0.cacert_len = cert.as_esp_idf_raw_len();
405                }
406
407                #[cfg(not(esp_idf_version_major = "4"))]
408                {
409                    config.0.servercert = cert.as_esp_idf_raw_ptr() as _;
410                    config.0.servercert_len = cert.as_esp_idf_raw_len();
411                }
412
413                config.0.prvtkey_pem = private_key.as_esp_idf_raw_ptr() as _;
414                config.0.prvtkey_len = private_key.as_esp_idf_raw_len();
415
416                esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?;
417            } else {
418                esp!(unsafe { httpd_ssl_start(handle_ref, &mut config.0) })?;
419            }
420        }
421
422        info!("Started Httpd server with config {conf:?}");
423
424        let server = Self {
425            sd: handle,
426            registrations: Vec::new(),
427            _reg: PhantomData,
428        };
429
430        CLOSE_HANDLERS.lock().insert(server.sd as _, Vec::new());
431
432        Ok(server)
433    }
434
435    /// Unregisters a URI.
436    fn unregister(&mut self, uri: CString, conf: httpd_uri_t) -> Result<(), EspIOError> {
437        unsafe {
438            esp!(httpd_unregister_uri_handler(
439                self.sd,
440                uri.as_ptr() as _,
441                conf.method
442            ))?;
443
444            let _drop = Box::from_raw(conf.user_ctx as *mut NativeHandler<'static>);
445        };
446
447        info!(
448            "Unregistered Httpd server handler {:?} for URI \"{}\"",
449            conf.method,
450            uri.to_str().unwrap()
451        );
452
453        Ok(())
454    }
455
456    /// Stops the server.
457    fn stop(&mut self) -> Result<(), EspIOError> {
458        if !self.sd.is_null() {
459            while let Some((uri, registration)) = self.registrations.pop() {
460                self.unregister(uri, registration)?;
461            }
462
463            // Maybe its better to always call httpd_stop because httpd_ssl_stop directly wraps httpd_stop anyways
464            // https://github.com/espressif/esp-idf/blob/e6fda46a02c41777f1d116a023fbec6a1efaffb9/components/esp_https_server/src/https_server.c#L268
465            #[cfg(not(esp_idf_esp_https_server_enable))]
466            esp!(unsafe { crate::sys::httpd_stop(self.sd) })?;
467
468            // httpd_ssl_stop doesn't return EspErr for some reason. It returns void.
469            #[cfg(all(esp_idf_esp_https_server_enable, esp_idf_version_major = "4"))]
470            unsafe {
471                crate::sys::httpd_ssl_stop(self.sd)
472            };
473
474            // esp-idf version 5 does return EspErr
475            #[cfg(all(esp_idf_esp_https_server_enable, not(esp_idf_version_major = "4")))]
476            esp!(unsafe { crate::sys::httpd_ssl_stop(self.sd) })?;
477
478            CLOSE_HANDLERS.lock().remove(&(self.sd as u32));
479
480            self.sd = ptr::null_mut();
481        }
482
483        info!("Httpd server stopped");
484
485        Ok(())
486    }
487
488    pub fn handler_chain<C>(&mut self, chain: C) -> Result<&mut Self, EspError>
489    where
490        C: EspHttpTraversableChain<'a>,
491    {
492        chain.accept(self)?;
493
494        Ok(self)
495    }
496
497    /// # Safety
498    ///
499    /// This method - in contrast to method `handler_chain` - allows the user to pass
500    /// a chain of non-static callbacks/closures. This enables users to borrow
501    /// - in the closure - variables that live on the stack - or more generally - in the same
502    ///   scope where the service is created.
503    ///
504    /// HOWEVER: care should be taken NOT to call `core::mem::forget()` on the service,
505    /// as that would immediately lead to an UB (crash).
506    /// Also note that forgetting the service might happen with `Rc` and `Arc`
507    /// when circular references are introduced: <https://github.com/rust-lang/rust/issues/24456>
508    ///
509    /// The reason is that the closure is actually sent to a hidden ESP IDF thread.
510    /// This means that if the service is forgotten, Rust is free to e.g. unwind the stack
511    /// and the closure now owned by this other thread will end up with references to variables that no longer exist.
512    ///
513    /// The destructor of the service takes care - prior to the service being dropped and e.g.
514    /// the stack being unwind - to remove the closure from the hidden thread and destroy it.
515    /// Unfortunately, when the service is forgotten, the un-subscription does not happen
516    /// and invalid references are left dangling.
517    ///
518    /// This "local borrowing" will only be possible to express in a safe way once/if `!Leak` types
519    /// are introduced to Rust (i.e. the impossibility to "forget" a type and thus not call its destructor).
520    pub unsafe fn handler_chain_nonstatic<C>(&mut self, chain: C) -> Result<&mut Self, EspError>
521    where
522        C: EspHttpTraversableChainNonstatic<'a>,
523    {
524        chain.accept(self)?;
525
526        Ok(self)
527    }
528
529    /// Registers a `Handler` for a URI and a method (GET, POST, etc).
530    pub fn handler<H>(
531        &mut self,
532        uri: &str,
533        method: Method,
534        handler: H,
535    ) -> Result<&mut Self, EspError>
536    where
537        H: for<'r> Handler<EspHttpConnection<'r>> + Send + 'static,
538    {
539        unsafe { self.handler_nonstatic(uri, method, handler) }
540    }
541
542    /// Registers a `Handler` for a URI and a method (GET, POST, etc).
543    ///
544    /// # Safety
545    ///
546    /// This method - in contrast to method `handler` - allows the user to pass
547    /// a non-static callback/closure. This enables users to borrow
548    /// - in the closure - variables that live on the stack - or more generally - in the same
549    ///   scope where the service is created.
550    ///
551    /// HOWEVER: care should be taken NOT to call `core::mem::forget()` on the service,
552    /// as that would immediately lead to an UB (crash).
553    /// Also note that forgetting the service might happen with `Rc` and `Arc`
554    /// when circular references are introduced: <https://github.com/rust-lang/rust/issues/24456>
555    ///
556    /// The reason is that the closure is actually sent to a hidden ESP IDF thread.
557    /// This means that if the service is forgotten, Rust is free to e.g. unwind the stack
558    /// and the closure now owned by this other thread will end up with references to variables that no longer exist.
559    ///
560    /// The destructor of the service takes care - prior to the service being dropped and e.g.
561    /// the stack being unwind - to remove the closure from the hidden thread and destroy it.
562    /// Unfortunately, when the service is forgotten, the un-subscription does not happen
563    /// and invalid references are left dangling.
564    ///
565    /// This "local borrowing" will only be possible to express in a safe way once/if `!Leak` types
566    /// are introduced to Rust (i.e. the impossibility to "forget" a type and thus not call its destructor).
567    pub unsafe fn handler_nonstatic<H>(
568        &mut self,
569        uri: &str,
570        method: Method,
571        handler: H,
572    ) -> Result<&mut Self, EspError>
573    where
574        H: for<'r> Handler<EspHttpConnection<'r>> + Send + 'a,
575    {
576        let c_str = to_cstring_arg(uri)?;
577
578        #[allow(clippy::needless_update)]
579        let conf = httpd_uri_t {
580            uri: c_str.as_ptr() as _,
581            method: Newtype::<ffi::c_uint>::from(method).0,
582            user_ctx: Box::into_raw(Box::new(self.to_native_handler(handler))) as *mut _,
583            handler: Some(EspHttpServer::handle_req),
584            ..Default::default()
585        };
586
587        esp!(unsafe { crate::sys::httpd_register_uri_handler(self.sd, &conf) })?;
588
589        info!(
590            "Registered Httpd server handler {:?} for URI \"{}\"",
591            method,
592            c_str.to_str().unwrap()
593        );
594
595        self.registrations.push((c_str, conf));
596
597        Ok(self)
598    }
599
600    /// Registers a function as the handler for the given URI and HTTP method (GET, POST, etc).
601    ///
602    /// The function will be called every time an HTTP client requests that URI
603    /// (via the appropriate HTTP method), receiving a different `Request` each
604    /// call. The `Request` contains a reference to the underlying `EspHttpConnection`.
605    pub fn fn_handler<E, F>(
606        &mut self,
607        uri: &str,
608        method: Method,
609        f: F,
610    ) -> Result<&mut Self, EspError>
611    where
612        F: for<'r> Fn(Request<&mut EspHttpConnection<'r>>) -> Result<(), E> + Send + 'static,
613        E: Debug,
614    {
615        unsafe { self.fn_handler_nonstatic(uri, method, f) }
616    }
617
618    /// Registers a function as the handler for the given URI and HTTP method (GET, POST, etc).
619    ///
620    /// The function will be called every time an HTTP client requests that URI
621    /// (via the appropriate HTTP method), receiving a different `Request` each
622    /// call. The `Request` contains a reference to the underlying `EspHttpConnection`.
623    ///
624    /// # Safety
625    ///
626    /// This method - in contrast to method `fn_handler` - allows the user to pass
627    /// a non-static callback/closure. This enables users to borrow
628    /// - in the closure - variables that live on the stack - or more generally - in the same
629    ///   scope where the service is created.
630    ///
631    /// HOWEVER: care should be taken NOT to call `core::mem::forget()` on the service,
632    /// as that would immediately lead to an UB (crash).
633    /// Also note that forgetting the service might happen with `Rc` and `Arc`
634    /// when circular references are introduced: <https://github.com/rust-lang/rust/issues/24456>
635    ///
636    /// The reason is that the closure is actually sent to a hidden ESP IDF thread.
637    /// This means that if the service is forgotten, Rust is free to e.g. unwind the stack
638    /// and the closure now owned by this other thread will end up with references to variables that no longer exist.
639    ///
640    /// The destructor of the service takes care - prior to the service being dropped and e.g.
641    /// the stack being unwind - to remove the closure from the hidden thread and destroy it.
642    /// Unfortunately, when the service is forgotten, the un-subscription does not happen
643    /// and invalid references are left dangling.
644    ///
645    /// This "local borrowing" will only be possible to express in a safe way once/if `!Leak` types
646    /// are introduced to Rust (i.e. the impossibility to "forget" a type and thus not call its destructor).
647    pub unsafe fn fn_handler_nonstatic<E, F>(
648        &mut self,
649        uri: &str,
650        method: Method,
651        f: F,
652    ) -> Result<&mut Self, EspError>
653    where
654        F: for<'r> Fn(Request<&mut EspHttpConnection<'r>>) -> Result<(), E> + Send + 'a,
655        E: Debug,
656    {
657        self.handler_nonstatic(uri, method, FnHandler::new(f))
658    }
659
660    fn to_native_handler<H>(&self, handler: H) -> NativeHandler<'a>
661    where
662        H: Handler<EspHttpConnection<'a>> + Send + 'a,
663    {
664        Box::new(move |raw_req| {
665            let mut connection = EspHttpConnection::new(unsafe { raw_req.as_mut().unwrap() });
666
667            let result = connection.invoke(&handler);
668
669            match result {
670                Ok(()) => {
671                    if let Err(e) = connection.complete() {
672                        connection.handle_error(e);
673                    }
674                }
675                Err(e) => {
676                    connection.handle_error(e);
677                    if let Err(e) = connection.complete() {
678                        connection.handle_error(e);
679                    }
680                }
681            }
682
683            ESP_OK as _
684        })
685    }
686
687    extern "C" fn handle_req(raw_req: *mut httpd_req_t) -> ffi::c_int {
688        let handler_ptr = (unsafe { *raw_req }).user_ctx as *mut NativeHandler<'static>;
689
690        let handler = unsafe { handler_ptr.as_ref() }.unwrap();
691
692        (handler)(raw_req)
693    }
694
695    extern "C" fn close_fn(sd: httpd_handle_t, sockfd: ffi::c_int) {
696        {
697            let mut sessions = OPEN_SESSIONS.lock();
698
699            if let Some(closed) = sessions.remove(&(sd as u32, sockfd)) {
700                closed.store(true, Ordering::SeqCst);
701            }
702        }
703
704        let all_close_handlers = CLOSE_HANDLERS.lock();
705
706        let close_handlers = all_close_handlers.get(&(sd as u32)).unwrap();
707
708        for close_handler in close_handlers {
709            (close_handler)(sockfd);
710        }
711        esp_nofail!(unsafe { close(sockfd) });
712    }
713}
714
715impl Drop for EspHttpServer<'_> {
716    fn drop(&mut self) {
717        self.stop().expect("Unable to stop the server cleanly");
718    }
719}
720
721impl RawHandle for EspHttpServer<'_> {
722    type Handle = httpd_handle_t;
723
724    fn handle(&self) -> Self::Handle {
725        self.sd
726    }
727}
728
729/// Wraps the given function into an `FnHandler`.
730///
731/// Do not confuse with `EspHttpServer::fn_handler`.
732pub fn fn_handler<F, E>(f: F) -> FnHandler<F>
733where
734    F: for<'a> Fn(Request<&mut EspHttpConnection<'a>>) -> Result<(), E> + Send,
735    E: Debug,
736{
737    FnHandler::new(f)
738}
739
740pub trait EspHttpTraversableChain<'a> {
741    fn accept(self, server: &mut EspHttpServer<'a>) -> Result<(), EspError>;
742}
743
744/// # Safety
745///
746/// Implementing this trait means that the chain can contain non-`'static` handlers
747/// and that the chain can be used with method `EspHttpServer::handler_chain_nonstatic`.
748///
749/// Consult the documentation of `EspHttpServer::handler_chain_nonstatic` for more
750/// information on how to use non-static handler chains.
751pub unsafe trait EspHttpTraversableChainNonstatic<'a>: EspHttpTraversableChain<'a> {}
752
753impl<'a> EspHttpTraversableChain<'a> for ChainRoot {
754    fn accept(self, _server: &mut EspHttpServer<'a>) -> Result<(), EspError> {
755        Ok(())
756    }
757}
758
759impl<'a, H, N> EspHttpTraversableChain<'a> for ChainHandler<H, N>
760where
761    H: for<'r> Handler<EspHttpConnection<'r>> + Send + 'static,
762    N: EspHttpTraversableChain<'a>,
763{
764    fn accept(self, server: &mut EspHttpServer<'a>) -> Result<(), EspError> {
765        self.next.accept(server)?;
766
767        server.handler(self.path, self.method, self.handler)?;
768
769        Ok(())
770    }
771}
772
773/// A newtype wrapper for `ChainHandler` that allows
774/// non-`'static`` handlers  in the chain to be registered
775/// and passed to the server.
776pub struct NonstaticChain<H, N>(ChainHandler<H, N>);
777
778impl<H, N> NonstaticChain<H, N> {
779    /// Wraps the given chain with a `NonstaticChain` newtype.
780    pub fn new(handler: ChainHandler<H, N>) -> Self {
781        Self(handler)
782    }
783}
784
785unsafe impl EspHttpTraversableChainNonstatic<'_> for ChainRoot {}
786
787impl<'a, H, N> EspHttpTraversableChain<'a> for NonstaticChain<H, N>
788where
789    H: for<'r> Handler<EspHttpConnection<'r>> + Send + 'a,
790    N: EspHttpTraversableChain<'a>,
791{
792    fn accept(self, server: &mut EspHttpServer<'a>) -> Result<(), EspError> {
793        self.0.next.accept(server)?;
794
795        unsafe {
796            server.handler_nonstatic(self.0.path, self.0.method, self.0.handler)?;
797        }
798
799        Ok(())
800    }
801}
802
803unsafe impl<'a, H, N> EspHttpTraversableChainNonstatic<'a> for NonstaticChain<H, N>
804where
805    H: for<'r> Handler<EspHttpConnection<'r>> + Send + 'a,
806    N: EspHttpTraversableChain<'a>,
807{
808}
809
810pub struct EspHttpRawConnection<'a>(&'a mut httpd_req_t);
811
812impl EspHttpRawConnection<'_> {
813    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, EspError> {
814        if !buf.is_empty() {
815            let fd = unsafe { httpd_req_to_sockfd(self.0) };
816            let len = unsafe { crate::sys::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) };
817
818            Ok(len as _)
819        } else {
820            Ok(0)
821        }
822    }
823
824    pub fn write(&mut self, buf: &[u8]) -> Result<usize, EspError> {
825        if !buf.is_empty() {
826            let fd = unsafe { httpd_req_to_sockfd(self.0) };
827            let len = unsafe { crate::sys::write(fd, buf.as_ptr() as *const _, buf.len()) };
828
829            Ok(len as _)
830        } else {
831            Ok(0)
832        }
833    }
834
835    pub fn write_all(&mut self, data: &[u8]) -> Result<(), EspError> {
836        let mut offset = 0;
837
838        while offset < data.len() {
839            offset += self.write(&data[offset..])?;
840        }
841
842        Ok(())
843    }
844
845    /// Retrieves the source IPv4 of the request.
846    ///
847    /// The IPv4 is retrieved using the underlying session socket.
848    #[cfg(esp_idf_lwip_ipv4)]
849    pub fn source_ipv4(&self) -> Result<Ipv4Addr, EspError> {
850        unsafe {
851            let sockfd = httpd_req_to_sockfd(self.handle());
852
853            if sockfd == -1 {
854                return Err(EspError::from_infallible::<ESP_FAIL>());
855            }
856
857            let mut addr = sockaddr_in {
858                sin_len: core::mem::size_of::<sockaddr_in>() as _,
859                sin_family: AF_INET as _,
860                ..Default::default()
861            };
862
863            esp!(lwip_getpeername(
864                sockfd,
865                &mut addr as *mut _ as *mut _,
866                &mut core::mem::size_of::<sockaddr_in>() as *mut _ as *mut _,
867            ))?;
868
869            Ok(Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr)))
870        }
871    }
872
873    /// Retrieves the source IPv6 of the request.
874    ///
875    /// The IPv6 is retrieved using the underlying session socket.
876    #[cfg(esp_idf_lwip_ipv6)]
877    pub fn source_ipv6(&self) -> Result<Ipv6Addr, EspError> {
878        unsafe {
879            let sockfd = httpd_req_to_sockfd(self.handle());
880
881            if sockfd == -1 {
882                return Err(EspError::from_infallible::<ESP_FAIL>());
883            }
884
885            let mut addr = sockaddr_in6 {
886                sin6_len: core::mem::size_of::<sockaddr_in6>() as _,
887                sin6_family: AF_INET6 as _,
888                ..Default::default()
889            };
890
891            esp!(lwip_getpeername(
892                sockfd,
893                &mut addr as *mut _ as *mut _,
894                &mut core::mem::size_of::<sockaddr_in6>() as *mut _ as *mut _,
895            ))?;
896
897            Ok(Ipv6Addr::from(addr.sin6_addr.un.u8_addr))
898        }
899    }
900}
901
902impl RawHandle for EspHttpRawConnection<'_> {
903    type Handle = *mut httpd_req_t;
904
905    fn handle(&self) -> Self::Handle {
906        self.0 as *const _ as *mut _
907    }
908}
909
910impl ErrorType for EspHttpRawConnection<'_> {
911    type Error = EspIOError;
912}
913
914impl Read for EspHttpRawConnection<'_> {
915    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
916        EspHttpRawConnection::read(self, buf).map_err(EspIOError)
917    }
918}
919
920impl Write for EspHttpRawConnection<'_> {
921    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
922        EspHttpRawConnection::write(self, buf).map_err(EspIOError)
923    }
924
925    fn flush(&mut self) -> Result<(), Self::Error> {
926        Ok(())
927    }
928}
929
930type EspHttpHeaders = BTreeMap<Uncased<'static>, String>;
931
932pub struct EspHttpConnection<'a> {
933    request: EspHttpRawConnection<'a>,
934    headers: Option<UnsafeCell<EspHttpHeaders>>,
935    response_headers: Option<Vec<CString>>,
936}
937
938/// Represents the two-way connection between an HTTP request and its response.
939impl<'a> EspHttpConnection<'a> {
940    fn new(raw_req: &'a mut httpd_req_t) -> Self {
941        Self {
942            request: EspHttpRawConnection(raw_req),
943            headers: Some(UnsafeCell::new(EspHttpHeaders::new())),
944            response_headers: None,
945        }
946    }
947
948    // Returns the URI for the current request in this connection.
949    pub fn uri(&self) -> &str {
950        self.assert_request();
951
952        let c_uri = unsafe { CStr::from_ptr(self.request.0.uri.as_ptr()) };
953
954        c_uri.to_str().unwrap()
955    }
956
957    // Returns the HTTP method for the current request in this connection.
958    pub fn method(&self) -> Method {
959        self.assert_request();
960
961        Method::from(Newtype(self.request.0.method as u32))
962    }
963
964    // Searches for the header of the given name in the HTTP request's headers.
965    pub fn header(&self, name: &str) -> Option<&str> {
966        self.assert_request();
967
968        let headers = self.headers.as_ref().unwrap();
969
970        if let Some(value) = unsafe { headers.get().as_ref().unwrap() }.get(UncasedStr::new(name)) {
971            Some(value.as_ref())
972        } else {
973            let raw_req = self.request.0 as *const httpd_req_t as *mut httpd_req_t;
974
975            if let Ok(c_name) = to_cstring_arg(name) {
976                match unsafe { httpd_req_get_hdr_value_len(raw_req, c_name.as_ptr() as _) } {
977                    0 => None,
978                    len => {
979                        // TODO: Would've been much more effective, if ESP-IDF was capable of returning a
980                        // pointer to the header value that is in the scratch buffer
981                        //
982                        // Check if we can implement it ourselves vy traversing the scratch buffer manually
983
984                        let mut buf: Vec<u8> = Vec::with_capacity(len + 1);
985
986                        esp_nofail!(unsafe {
987                            httpd_req_get_hdr_value_str(
988                                raw_req,
989                                c_name.as_ptr(),
990                                buf.as_mut_ptr().cast(),
991                                len + 1,
992                            )
993                        });
994
995                        unsafe {
996                            buf.set_len(len + 1);
997                        }
998
999                        // TODO: Replace with a proper conversion from ISO-8859-1 to UTF8
1000                        let value = String::from_utf8_lossy(&buf[..len]).into_owned();
1001                        unsafe { headers.get().as_mut().unwrap() }
1002                            .insert(Uncased::from(name.to_owned()), value);
1003
1004                        unsafe { headers.get().as_ref().unwrap() }
1005                            .get(UncasedStr::new(name))
1006                            .map(|s| s.as_ref())
1007                    }
1008                }
1009            } else {
1010                None
1011            }
1012        }
1013    }
1014
1015    pub fn split(&mut self) -> (&EspHttpConnection<'a>, &mut Self) {
1016        self.assert_request();
1017
1018        let headers_ptr: *const EspHttpConnection<'a> = self as *const _;
1019
1020        let headers = unsafe { headers_ptr.as_ref().unwrap() };
1021
1022        (headers, self)
1023    }
1024
1025    /// Sends the HTTP status (e.g. "200 OK") and the response headers to the
1026    /// HTTP client.
1027    pub fn initiate_response(
1028        &mut self,
1029        status: u16,
1030        message: Option<&str>,
1031        headers: &[(&str, &str)],
1032    ) -> Result<(), EspError> {
1033        self.assert_request();
1034
1035        let mut c_headers = Vec::new();
1036
1037        let status = if let Some(message) = message {
1038            format!("{status} {message}")
1039        } else {
1040            status.to_string()
1041        };
1042
1043        let c_status = to_cstring_arg(status.as_str())?;
1044        esp!(unsafe { httpd_resp_set_status(self.request.0, c_status.as_ptr() as _) })?;
1045
1046        c_headers.push(c_status);
1047
1048        for (key, value) in headers {
1049            if key.eq_ignore_ascii_case("Content-Type") {
1050                let c_type = to_cstring_arg(value)?;
1051
1052                esp!(unsafe { httpd_resp_set_type(self.request.0, c_type.as_c_str().as_ptr()) })?;
1053
1054                c_headers.push(c_type);
1055            } else if key.eq_ignore_ascii_case("Content-Length") {
1056                let c_len = to_cstring_arg(value)?;
1057
1058                //esp!(unsafe { httpd_resp_set_len(self.raw_req, c_len.as_c_str().as_ptr()) })?;
1059
1060                c_headers.push(c_len);
1061            } else {
1062                let name = to_cstring_arg(key)?;
1063                let value = to_cstring_arg(value)?;
1064
1065                esp!(unsafe {
1066                    httpd_resp_set_hdr(
1067                        self.request.0,
1068                        name.as_c_str().as_ptr() as _,
1069                        value.as_c_str().as_ptr() as _,
1070                    )
1071                })?;
1072
1073                c_headers.push(name);
1074                c_headers.push(value);
1075            }
1076        }
1077
1078        self.response_headers = Some(c_headers);
1079        self.headers = None;
1080
1081        Ok(())
1082    }
1083
1084    /// Returns `true` if the response headers have been sent to the HTTP client.
1085    pub fn is_response_initiated(&self) -> bool {
1086        self.headers.is_none()
1087    }
1088
1089    /// Reads bytes from the body of the HTTP request.
1090    ///
1091    /// This is typically used whenever the HTTP server has to parse the body
1092    /// of an HTTP POST request.
1093    ///
1094    /// ```ignore
1095    /// server.fn_handler("/foo", Method::Post, move |mut request| {
1096    ///     let (_headers, connection) = request.split();
1097    ///     let mut buffer: [u8; 1024] = [0; 1024];
1098    ///     let bytes_read = connection.read(&mut buffer)?;
1099    ///
1100    ///     let my_data = MyDataStruct::from_bytes(&buffer[0..bytes_read]);
1101    ///     // etc
1102    ///
1103    ///     Ok(())
1104    /// })?;
1105    /// ```
1106    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, EspError> {
1107        self.assert_request();
1108
1109        unsafe {
1110            let len = httpd_req_recv(self.request.0, buf.as_mut_ptr() as *mut _, buf.len());
1111
1112            if len < 0 {
1113                esp!(len)?;
1114            }
1115
1116            Ok(len as usize)
1117        }
1118    }
1119
1120    /// Sends bytes back to the HTTP client; returns the number of bytes sent.
1121    pub fn write(&mut self, buf: &[u8]) -> Result<usize, EspError> {
1122        self.assert_response();
1123
1124        if !buf.is_empty() {
1125            esp!(unsafe {
1126                httpd_resp_send_chunk(self.request.0, buf.as_ptr().cast(), buf.len() as isize)
1127            })?;
1128
1129            self.response_headers = None;
1130        }
1131
1132        Ok(buf.len())
1133    }
1134
1135    // Sends bytes back to the HTTP client (as per `EspHttpConnection::write`),
1136    // does *not* return the number of bytes sent.
1137    pub fn write_all(&mut self, buf: &[u8]) -> Result<(), EspError> {
1138        self.write(buf)?;
1139
1140        Ok(())
1141    }
1142
1143    pub fn raw_connection(&mut self) -> Result<&mut EspHttpRawConnection<'a>, EspError> {
1144        Ok(&mut self.request)
1145    }
1146
1147    fn invoke<H>(&mut self, handler: &H) -> Result<(), H::Error>
1148    where
1149        H: Handler<Self>,
1150    {
1151        // TODO info!("About to handle query string {:?}", self.query_string());
1152
1153        handler.handle(self)?;
1154
1155        Ok(())
1156    }
1157
1158    fn complete(&mut self) -> Result<(), EspError> {
1159        let buf = &[];
1160
1161        if self.response_headers.is_some() {
1162            esp!(unsafe { httpd_resp_send(self.request.0, buf.as_ptr() as *const _, 0) })?;
1163        } else {
1164            esp!(unsafe { httpd_resp_send_chunk(self.request.0, buf.as_ptr() as *const _, 0) })?;
1165        }
1166
1167        self.response_headers = None;
1168
1169        Ok(())
1170    }
1171
1172    fn handle_error<E>(&mut self, error: E)
1173    where
1174        E: Debug,
1175    {
1176        if self.headers.is_some() {
1177            info!("About to handle internal error [{error:?}], response not sent yet");
1178
1179            if let Err(error2) = self.render_error(&error) {
1180                warn!(
1181                    "Internal error[{error2}] while rendering another internal error:\n{error:?}"
1182                );
1183            }
1184        } else {
1185            warn!("Unhandled internal error [{error:?}], response is already sent");
1186        }
1187    }
1188
1189    fn render_error<E>(&mut self, error: E) -> Result<(), EspError>
1190    where
1191        E: Debug,
1192    {
1193        self.initiate_response(500, Some("Internal Error"), &[content_type("text/html")])?;
1194
1195        self.write_all(
1196            format!(
1197                r#"
1198                    <!DOCTYPE html5>
1199                    <html>
1200                        <body style="font-family: Verdana, Sans;">
1201                            <h1>INTERNAL ERROR</h1>
1202                            <hr>
1203                            <pre>{error:?}</pre>
1204                        <body>
1205                    </html>
1206                "#
1207            )
1208            .as_bytes(),
1209        )?;
1210
1211        Ok(())
1212    }
1213
1214    fn assert_request(&self) {
1215        if self.headers.is_none() {
1216            panic!("connection is not in request phase");
1217        }
1218    }
1219
1220    fn assert_response(&self) {
1221        if self.headers.is_some() {
1222            panic!("connection is not in response phase");
1223        }
1224    }
1225}
1226
1227impl RawHandle for EspHttpConnection<'_> {
1228    type Handle = *mut httpd_req_t;
1229
1230    fn handle(&self) -> Self::Handle {
1231        self.request.handle()
1232    }
1233}
1234
1235impl embedded_svc::http::Query for EspHttpConnection<'_> {
1236    fn uri(&self) -> &str {
1237        EspHttpConnection::uri(self)
1238    }
1239
1240    fn method(&self) -> Method {
1241        EspHttpConnection::method(self)
1242    }
1243}
1244
1245impl embedded_svc::http::Headers for EspHttpConnection<'_> {
1246    fn header(&self, name: &str) -> Option<&str> {
1247        EspHttpConnection::header(self, name)
1248    }
1249}
1250
1251impl ErrorType for EspHttpConnection<'_> {
1252    type Error = EspIOError;
1253}
1254
1255impl Read for EspHttpConnection<'_> {
1256    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
1257        EspHttpConnection::read(self, buf).map_err(EspIOError)
1258    }
1259}
1260
1261impl Write for EspHttpConnection<'_> {
1262    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1263        EspHttpConnection::write(self, buf).map_err(EspIOError)
1264    }
1265
1266    fn flush(&mut self) -> Result<(), Self::Error> {
1267        self.assert_response();
1268
1269        Ok(())
1270    }
1271}
1272
1273impl<'b> Connection for EspHttpConnection<'b> {
1274    type Headers = Self;
1275
1276    type Read = Self;
1277
1278    type RawConnectionError = EspIOError;
1279
1280    type RawConnection = EspHttpRawConnection<'b>;
1281
1282    fn split(&mut self) -> (&Self::Headers, &mut Self::Read) {
1283        EspHttpConnection::split(self)
1284    }
1285
1286    fn initiate_response<'a>(
1287        &'a mut self,
1288        status: u16,
1289        message: Option<&'a str>,
1290        headers: &'a [(&'a str, &'a str)],
1291    ) -> Result<(), Self::Error> {
1292        EspHttpConnection::initiate_response(self, status, message, headers).map_err(EspIOError)
1293    }
1294
1295    fn is_response_initiated(&self) -> bool {
1296        EspHttpConnection::is_response_initiated(self)
1297    }
1298
1299    fn raw_connection(&mut self) -> Result<&mut Self::RawConnection, Self::Error> {
1300        EspHttpConnection::raw_connection(self).map_err(EspIOError)
1301    }
1302}
1303
1304#[cfg(esp_idf_httpd_ws_support)]
1305pub mod ws {
1306    use core::ffi;
1307    use core::fmt::Debug;
1308    use core::sync::atomic::{AtomicBool, Ordering};
1309
1310    extern crate alloc;
1311    use alloc::boxed::Box;
1312    use alloc::sync::Arc;
1313
1314    use ::log::*;
1315
1316    use embedded_svc::http::Method;
1317    use embedded_svc::ws::*;
1318
1319    use crate::sys::*;
1320
1321    use crate::private::common::Newtype;
1322    use crate::private::cstr::to_cstring_arg;
1323    use crate::private::mutex::{Condvar, Mutex};
1324
1325    use super::EspHttpServer;
1326    use super::CLOSE_HANDLERS;
1327    use super::OPEN_SESSIONS;
1328    use super::{CloseHandler, NativeHandler};
1329
1330    /// A Websocket connection between this server and a client.
1331    pub enum EspHttpWsConnection {
1332        New(httpd_handle_t, *mut httpd_req_t),
1333        Receiving(httpd_handle_t, *mut httpd_req_t, Option<httpd_ws_frame_t>),
1334        Closed(ffi::c_int),
1335    }
1336
1337    impl EspHttpWsConnection {
1338        // Returns the internal file descriptor for the socket.
1339        pub fn session(&self) -> i32 {
1340            match self {
1341                Self::New(_, raw_req) | Self::Receiving(_, raw_req, _) => unsafe {
1342                    httpd_req_to_sockfd(*raw_req)
1343                },
1344                Self::Closed(fd) => *fd,
1345            }
1346        }
1347
1348        /// Returns `true` when the connection still hasn't received any data
1349        pub fn is_new(&self) -> bool {
1350            matches!(self, Self::New(_, _))
1351        }
1352
1353        /// Returns `true` when the connection already has been closed.
1354        pub fn is_closed(&self) -> bool {
1355            matches!(self, Self::Closed(_))
1356        }
1357
1358        pub fn create_detached_sender(&self) -> Result<EspHttpWsDetachedSender, EspError> {
1359            match self {
1360                Self::New(sd, raw_req) | Self::Receiving(sd, raw_req, _) => {
1361                    let fd = unsafe { httpd_req_to_sockfd(*raw_req) };
1362
1363                    let mut sessions = OPEN_SESSIONS.lock();
1364
1365                    let closed = sessions
1366                        .entry((*sd as u32, fd))
1367                        .or_insert_with(|| Arc::new(AtomicBool::new(false)));
1368
1369                    Ok(EspHttpWsDetachedSender::new(*sd, fd, closed.clone()))
1370                }
1371                Self::Closed(_) => Err(EspError::from_infallible::<ESP_FAIL>()),
1372            }
1373        }
1374
1375        /// Sends a frame to the client.
1376        pub fn send(&mut self, frame_type: FrameType, frame_data: &[u8]) -> Result<(), EspError> {
1377            match self {
1378                Self::New(_, raw_req) | Self::Receiving(_, raw_req, _) => {
1379                    let raw_frame = Self::create_raw_frame(frame_type, frame_data);
1380
1381                    esp!(unsafe {
1382                        httpd_ws_send_frame(*raw_req, &raw_frame as *const _ as *mut _)
1383                    })?;
1384
1385                    Ok(())
1386                }
1387                _ => Err(EspError::from_infallible::<ESP_FAIL>()),
1388            }
1389        }
1390
1391        /// Receives a frame from the client.
1392        pub fn recv(&mut self, frame_data_buf: &mut [u8]) -> Result<(FrameType, usize), EspError> {
1393            match self {
1394                Self::New(_, _) => Err(EspError::from_infallible::<ESP_FAIL>()),
1395                Self::Receiving(_, raw_req, ref mut raw_frame_mut) => {
1396                    let raw_frame = loop {
1397                        if let Some(raw_frame) = raw_frame_mut.as_mut() {
1398                            break raw_frame;
1399                        }
1400
1401                        let mut raw_frame: httpd_ws_frame_t = Default::default();
1402
1403                        esp!(unsafe {
1404                            httpd_ws_recv_frame(*raw_req, &mut raw_frame as *mut _, 0)
1405                        })?;
1406
1407                        // This is necessary because the ESP IDF WS API requires us to
1408                        // call it exactly once with a frame that has a zero-sized buffer,
1409                        // and then also exactly once with the same frame instance, except
1410                        // its buffer set to a non-zero size
1411                        //
1412                        // On the other hand, we would like to allow the user the freedom
1413                        // to call the API as many times as she wants, and only consume the
1414                        // frame if the provided buffer is big enough
1415                        *raw_frame_mut = Some(raw_frame);
1416                    };
1417
1418                    let (frame_type, len) = Self::create_frame_type(raw_frame);
1419
1420                    if frame_data_buf.len() >= len {
1421                        raw_frame.payload = frame_data_buf.as_mut_ptr() as *mut _;
1422                        esp!(unsafe { httpd_ws_recv_frame(*raw_req, raw_frame as *mut _, len) })?;
1423
1424                        *raw_frame_mut = None;
1425                    }
1426
1427                    Ok((frame_type, len))
1428                }
1429                Self::Closed(_) => Ok((FrameType::SocketClose, 0)),
1430            }
1431        }
1432
1433        #[allow(clippy::needless_update)]
1434        fn create_raw_frame(frame_type: FrameType, frame_data: &[u8]) -> httpd_ws_frame_t {
1435            httpd_ws_frame_t {
1436                type_: match frame_type {
1437                    FrameType::Text(_) => httpd_ws_type_t_HTTPD_WS_TYPE_TEXT,
1438                    FrameType::Binary(_) => httpd_ws_type_t_HTTPD_WS_TYPE_BINARY,
1439                    FrameType::Ping => httpd_ws_type_t_HTTPD_WS_TYPE_PING,
1440                    FrameType::Pong => httpd_ws_type_t_HTTPD_WS_TYPE_PONG,
1441                    FrameType::Close => httpd_ws_type_t_HTTPD_WS_TYPE_CLOSE,
1442                    FrameType::Continue(_) => httpd_ws_type_t_HTTPD_WS_TYPE_CONTINUE,
1443                    FrameType::SocketClose => panic!("Cannot send SocketClose as a frame"),
1444                },
1445                final_: frame_type.is_final(),
1446                fragmented: frame_type.is_fragmented(),
1447                payload: frame_data.as_ptr() as *const _ as *mut _,
1448                len: frame_data.len(),
1449                ..Default::default()
1450            }
1451        }
1452
1453        #[allow(non_upper_case_globals)]
1454        fn create_frame_type(raw_frame: &httpd_ws_frame_t) -> (FrameType, usize) {
1455            match raw_frame.type_ {
1456                httpd_ws_type_t_HTTPD_WS_TYPE_TEXT => {
1457                    (FrameType::Text(raw_frame.fragmented), raw_frame.len + 1)
1458                }
1459                httpd_ws_type_t_HTTPD_WS_TYPE_BINARY => {
1460                    (FrameType::Binary(raw_frame.fragmented), raw_frame.len)
1461                }
1462                httpd_ws_type_t_HTTPD_WS_TYPE_CONTINUE => {
1463                    (FrameType::Continue(raw_frame.final_), raw_frame.len)
1464                }
1465                httpd_ws_type_t_HTTPD_WS_TYPE_PING => (FrameType::Ping, 0),
1466                httpd_ws_type_t_HTTPD_WS_TYPE_PONG => (FrameType::Pong, 0),
1467                httpd_ws_type_t_HTTPD_WS_TYPE_CLOSE => (FrameType::Close, 0),
1468                _ => panic!("Unknown frame type: {}", raw_frame.type_),
1469            }
1470        }
1471    }
1472
1473    impl ErrorType for EspHttpWsConnection {
1474        type Error = EspError;
1475    }
1476
1477    impl Sender for EspHttpWsConnection {
1478        fn send(&mut self, frame_type: FrameType, frame_data: &[u8]) -> Result<(), Self::Error> {
1479            EspHttpWsConnection::send(self, frame_type, frame_data)
1480        }
1481    }
1482
1483    impl Receiver for EspHttpWsConnection {
1484        fn recv(&mut self, frame_data_buf: &mut [u8]) -> Result<(FrameType, usize), Self::Error> {
1485            EspHttpWsConnection::recv(self, frame_data_buf)
1486        }
1487    }
1488
1489    struct EspWsDetachedSendRequest {
1490        sd: httpd_handle_t,
1491        fd: ffi::c_int,
1492
1493        closed: Arc<AtomicBool>,
1494
1495        raw_frame: *const httpd_ws_frame_t,
1496
1497        error_code: Mutex<Option<u32>>,
1498        condvar: Condvar,
1499    }
1500
1501    pub struct EspHttpWsDetachedSender {
1502        sd: httpd_handle_t,
1503        fd: ffi::c_int,
1504        closed: Arc<AtomicBool>,
1505    }
1506
1507    impl EspHttpWsDetachedSender {
1508        fn new(sd: httpd_handle_t, fd: ffi::c_int, closed: Arc<AtomicBool>) -> Self {
1509            Self { sd, fd, closed }
1510        }
1511
1512        pub fn session(&self) -> i32 {
1513            self.fd
1514        }
1515
1516        pub fn is_new(&self) -> bool {
1517            false
1518        }
1519
1520        pub fn is_closed(&self) -> bool {
1521            self.closed.load(Ordering::SeqCst)
1522        }
1523
1524        pub fn send(&mut self, frame_type: FrameType, frame_data: &[u8]) -> Result<(), EspError> {
1525            if !self.closed.load(Ordering::SeqCst) {
1526                let raw_frame = EspHttpWsConnection::create_raw_frame(frame_type, frame_data);
1527
1528                let send_request = EspWsDetachedSendRequest {
1529                    sd: self.sd,
1530                    fd: self.fd,
1531
1532                    closed: self.closed.clone(),
1533
1534                    raw_frame: &raw_frame as *const _,
1535
1536                    error_code: Mutex::new(None),
1537                    condvar: Condvar::new(),
1538                };
1539
1540                esp!(unsafe {
1541                    httpd_queue_work(
1542                        self.sd,
1543                        Some(Self::enqueue),
1544                        &send_request as *const _ as *mut _,
1545                    )
1546                })?;
1547
1548                let mut guard = send_request.error_code.lock();
1549
1550                while guard.is_none() {
1551                    guard = send_request.condvar.wait(guard);
1552                }
1553
1554                esp!((*guard).unwrap())?;
1555            } else {
1556                return Err(EspError::from_infallible::<ESP_FAIL>());
1557            }
1558
1559            Ok(())
1560        }
1561
1562        extern "C" fn enqueue(arg: *mut ffi::c_void) {
1563            let request = unsafe { (arg as *const EspWsDetachedSendRequest).as_ref().unwrap() };
1564
1565            let ret = if !request.closed.load(Ordering::SeqCst) {
1566                unsafe {
1567                    httpd_ws_send_frame_async(
1568                        request.sd,
1569                        request.fd,
1570                        request.raw_frame as *const _ as *mut _,
1571                    )
1572                }
1573            } else {
1574                ESP_FAIL
1575            };
1576
1577            let mut guard = request.error_code.lock();
1578
1579            *guard = Some(ret as _);
1580
1581            request.condvar.notify_all();
1582        }
1583    }
1584
1585    unsafe impl Send for EspHttpWsDetachedSender {}
1586
1587    impl Clone for EspHttpWsDetachedSender {
1588        fn clone(&self) -> Self {
1589            Self {
1590                sd: self.sd,
1591                fd: self.fd,
1592                closed: self.closed.clone(),
1593            }
1594        }
1595    }
1596
1597    impl ErrorType for EspHttpWsDetachedSender {
1598        type Error = EspError;
1599    }
1600
1601    impl Sender for EspHttpWsDetachedSender {
1602        fn send(&mut self, frame_type: FrameType, frame_data: &[u8]) -> Result<(), Self::Error> {
1603            EspHttpWsDetachedSender::send(self, frame_type, frame_data)
1604        }
1605    }
1606
1607    impl<'a> EspHttpServer<'a> {
1608        /// Registers a function as the handler for a Websockets URI.
1609        ///
1610        /// The function will be called every time a Websockets connection is
1611        /// made to that URI, receiving a different `EspHttpWsConnection` each
1612        /// call.
1613        ///
1614        /// # Arguments
1615        ///
1616        /// * `uri` - The URI to connect to
1617        /// * `subprotocol_list` - An optional string slice containing a comma-separated
1618        ///   list of subprotocols to be supported by this handler
1619        /// * handler: the handler
1620        ///
1621        /// Note that Websockets functionality is gated behind an SDK flag.
1622        /// See [`crate::ws`](esp-idf-svc::ws)
1623        pub fn ws_handler<H, E>(
1624            &mut self,
1625            uri: &str,
1626            subprotocol_list: Option<&str>,
1627            handler: H,
1628        ) -> Result<&mut Self, EspError>
1629        where
1630            H: for<'r> Fn(&'r mut EspHttpWsConnection) -> Result<(), E> + Send + Sync + 'a,
1631            E: Debug,
1632        {
1633            let uri_c_str = to_cstring_arg(uri)?;
1634
1635            let (req_handler, close_handler) = self.to_native_ws_handler(self.sd, handler);
1636
1637            let mut conf = httpd_uri_t {
1638                uri: uri_c_str.as_ptr() as _,
1639                method: Newtype::<ffi::c_uint>::from(Method::Get).0,
1640                user_ctx: Box::into_raw(Box::new(req_handler)) as *mut _,
1641                handler: Some(EspHttpServer::handle_req),
1642                is_websocket: true,
1643                // TODO: Expose as a parameter in future: handle_ws_control_frames: true,
1644                ..Default::default()
1645            };
1646
1647            let subproto_c_str; // SAFETY: same scope as httpd_register_uri_handler required!
1648            if let Some(subprotocol_list) = subprotocol_list {
1649                subproto_c_str = to_cstring_arg(subprotocol_list)?;
1650                conf.supported_subprotocol = subproto_c_str.as_ptr();
1651            }
1652
1653            esp!(unsafe { crate::sys::httpd_register_uri_handler(self.sd, &conf) })?;
1654
1655            {
1656                let mut all_close_handlers = CLOSE_HANDLERS.lock();
1657
1658                let close_handlers = all_close_handlers.get_mut(&(self.sd as u32)).unwrap();
1659
1660                let close_handler: CloseHandler<'static> =
1661                    unsafe { core::mem::transmute(close_handler) };
1662
1663                close_handlers.push(close_handler);
1664            }
1665
1666            info!(
1667                "Registered Httpd server WS handler for URI \"{}\"",
1668                uri_c_str.to_str().unwrap()
1669            );
1670
1671            self.registrations.push((uri_c_str, conf));
1672
1673            Ok(self)
1674        }
1675
1676        fn handle_ws_request<H, E>(
1677            connection: &mut EspHttpWsConnection,
1678            handler: &H,
1679        ) -> Result<(), E>
1680        where
1681            H: for<'b> Fn(&'b mut EspHttpWsConnection) -> Result<(), E> + Send + 'a,
1682            E: Debug,
1683        {
1684            handler(connection)?;
1685
1686            Ok(())
1687        }
1688
1689        fn handle_ws_error<E>(error: E) -> ffi::c_int
1690        where
1691            E: Debug,
1692        {
1693            warn!("Unhandled internal error [{error:?}]:\n{error:?}");
1694
1695            ESP_OK as _
1696        }
1697
1698        fn to_native_ws_handler<H, E>(
1699            &self,
1700            server_handle: httpd_handle_t,
1701            handler: H,
1702        ) -> (NativeHandler<'a>, CloseHandler<'a>)
1703        where
1704            H: for<'r> Fn(&'r mut EspHttpWsConnection) -> Result<(), E> + Send + Sync + 'a,
1705            E: Debug,
1706        {
1707            let boxed_handler = Arc::new(move |mut connection: EspHttpWsConnection| {
1708                let result = Self::handle_ws_request(&mut connection, &handler);
1709
1710                match result {
1711                    Ok(()) => ESP_OK as _,
1712                    Err(e) => Self::handle_ws_error(e),
1713                }
1714            });
1715
1716            let req_handler = {
1717                let boxed_handler = boxed_handler.clone();
1718
1719                Box::new(move |raw_req: *mut httpd_req_t| {
1720                    let req = unsafe { raw_req.as_ref() }.unwrap();
1721
1722                    (boxed_handler)(if req.method == http_method_HTTP_GET as i32 {
1723                        EspHttpWsConnection::New(server_handle, raw_req)
1724                    } else {
1725                        EspHttpWsConnection::Receiving(server_handle, raw_req, None)
1726                    })
1727                })
1728            };
1729
1730            let close_handler = Box::new(move |fd| {
1731                (boxed_handler)(EspHttpWsConnection::Closed(fd));
1732            });
1733
1734            (req_handler, close_handler)
1735        }
1736    }
1737
1738    // TODO: Consider if it makes sense at all to put a complex async layer on top of the ESP-IDF WS API,
1739    // which is very far from being async
1740    // TODO: Port all of the code below to `zerocopy`, thus simplifying it and providing blocking
1741    // sender/receiver/acceptor implementations as well
1742
1743    // enum ReceiverData {
1744    //     None,
1745    //     Metadata((FrameType, usize)),
1746    //     Data(*mut u8),
1747    //     DataCopied,
1748    //     Closed,
1749    // }
1750
1751    // unsafe impl Send for ReceiverData {}
1752
1753    // struct SharedReceiverState {
1754    //     waker: Option<Waker>,
1755    //     data: ReceiverData,
1756    // }
1757
1758    // struct ConnectionState {
1759    //     session: ffi::c_int,
1760    //     receiver_state: Arc<Mutex<SharedReceiverState>>,
1761    // }
1762
1763    // pub struct SharedAcceptorState {
1764    //     waker: Option<Waker>,
1765    //     data: Option<Option<(Arc<Mutex<SharedReceiverState>>, EspHttpWsDetachedSender)>>,
1766    // }
1767
1768    // pub struct EspHttpWsAsyncSender<U> {
1769    //     unblocker: U,
1770    //     sender: EspHttpWsDetachedSender,
1771    // }
1772
1773    // impl<U> EspHttpWsAsyncSender<U>
1774    // where
1775    //     U: Unblocker,
1776    // {
1777    //     pub async fn send(
1778    //         &mut self,
1779    //         frame_type: FrameType,
1780    //         frame_data: &[u8],
1781    //     ) -> Result<(), EspError> {
1782    //         #[cfg(not(feature = "std"))]
1783    //         use alloc::borrow::ToOwned;
1784
1785    //         debug!(
1786    //             "Sending data (frame_type={:?}, frame_len={}) to WS connection {:?}",
1787    //             frame_type,
1788    //             frame_data.len(),
1789    //             self.sender.session()
1790    //         );
1791
1792    //         let mut sender = self.sender.clone();
1793    //         let frame_data: alloc::vec::Vec<u8> = frame_data.to_owned();
1794
1795    //         self.unblocker
1796    //             .unblock(move || sender.send(frame_type, &frame_data))
1797    //             .await
1798    //     }
1799    // }
1800
1801    // impl<U> ErrorType for EspHttpWsAsyncSender<U> {
1802    //     type Error = EspError;
1803    // }
1804
1805    // impl<U> asynch::Sender for EspHttpWsAsyncSender<U>
1806    // where
1807    //     U: Unblocker,
1808    // {
1809    //     async fn send(
1810    //         &mut self,
1811    //         frame_type: FrameType,
1812    //         frame_data: &[u8],
1813    //     ) -> Result<(), Self::Error> {
1814    //         EspHttpWsAsyncSender::send(self, frame_type, frame_data).await
1815    //     }
1816    // }
1817
1818    // pub struct EspHttpWsAsyncReceiver {
1819    //     shared: Arc<Mutex<SharedReceiverState>>,
1820    //     condvar: Arc<Condvar>,
1821    // }
1822
1823    // impl EspHttpWsAsyncReceiver {
1824    //     pub async fn recv(
1825    //         &mut self,
1826    //         frame_data_buf: &mut [u8],
1827    //     ) -> Result<(FrameType, usize), EspError> {
1828    //         AsyncReceiverFuture {
1829    //             receiver: self,
1830    //             frame_data_buf,
1831    //         }
1832    //         .await
1833    //     }
1834    // }
1835
1836    // struct AsyncReceiverFuture<'a> {
1837    //     receiver: &'a mut EspHttpWsAsyncReceiver,
1838    //     frame_data_buf: &'a mut [u8],
1839    // }
1840
1841    // impl<'a> Future for AsyncReceiverFuture<'a> {
1842    //     type Output = Result<(FrameType, usize), EspError>;
1843
1844    //     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1845    //         let frame_data_buf_ptr = self.frame_data_buf.as_mut_ptr();
1846    //         let mut shared = self.receiver.shared.lock();
1847
1848    //         if let ReceiverData::Metadata((frame_type, size)) = shared.data {
1849    //             if self.frame_data_buf.len() >= size {
1850    //                 shared.data = ReceiverData::Data(frame_data_buf_ptr);
1851
1852    //                 self.receiver.condvar.notify_all();
1853
1854    //                 while !matches!(shared.data, ReceiverData::DataCopied) {
1855    //                     shared = self.receiver.condvar.wait(shared);
1856    //                 }
1857
1858    //                 shared.data = ReceiverData::None;
1859    //                 self.receiver.condvar.notify_all();
1860    //             }
1861
1862    //             Poll::Ready(Ok((frame_type, size)))
1863    //         } else if let ReceiverData::Closed = shared.data {
1864    //             Poll::Ready(Ok((FrameType::Close, 0)))
1865    //         } else {
1866    //             shared.waker = Some(cx.waker().clone());
1867    //             Poll::Pending
1868    //         }
1869    //     }
1870    // }
1871
1872    // impl ErrorType for EspHttpWsAsyncReceiver {
1873    //     type Error = EspError;
1874    // }
1875
1876    // impl asynch::Receiver for EspHttpWsAsyncReceiver {
1877    //     async fn recv(
1878    //         &mut self,
1879    //         frame_data_buf: &mut [u8],
1880    //     ) -> Result<(FrameType, usize), Self::Error> {
1881    //         EspHttpWsAsyncReceiver::recv(self, frame_data_buf).await
1882    //     }
1883    // }
1884
1885    // pub struct EspHttpWsAsyncAcceptor<U> {
1886    //     unblocker: U,
1887    //     accept: Arc<Mutex<SharedAcceptorState>>,
1888    //     condvar: Arc<Condvar>,
1889    // }
1890
1891    // impl<U> EspHttpWsAsyncAcceptor<U> {
1892    //     pub fn accept(&self) -> &EspHttpWsAsyncAcceptor<U> {
1893    //         self
1894    //     }
1895    // }
1896
1897    // impl<'a, U> Future for &'a EspHttpWsAsyncAcceptor<U>
1898    // where
1899    //     U: Clone,
1900    // {
1901    //     type Output = Result<(EspHttpWsAsyncSender<U>, EspHttpWsAsyncReceiver), EspError>;
1902
1903    //     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1904    //         let mut accept = self.accept.lock();
1905
1906    //         match accept.data.take() {
1907    //             Some(Some((shared, sender))) => {
1908    //                 let sender = EspHttpWsAsyncSender {
1909    //                     unblocker: self.unblocker.clone(),
1910    //                     sender,
1911    //                 };
1912
1913    //                 let receiver = EspHttpWsAsyncReceiver {
1914    //                     shared,
1915    //                     condvar: self.condvar.clone(),
1916    //                 };
1917
1918    //                 self.condvar.notify_all();
1919
1920    //                 Poll::Ready(Ok((sender, receiver)))
1921    //             }
1922    //             Some(None) => {
1923    //                 accept.data = Some(None);
1924    //                 Poll::Pending
1925    //             }
1926    //             None => {
1927    //                 accept.waker = Some(cx.waker().clone());
1928    //                 Poll::Pending
1929    //             }
1930    //         }
1931    //     }
1932    // }
1933
1934    // impl<U> ErrorType for EspHttpWsAsyncAcceptor<U> {
1935    //     type Error = EspError;
1936    // }
1937
1938    // impl<U> asynch::server::Acceptor for EspHttpWsAsyncAcceptor<U>
1939    // where
1940    //     U: Unblocker + Clone + Send,
1941    // {
1942    //     type Sender<'a> = EspHttpWsAsyncSender<U> where U: 'a;
1943    //     type Receiver<'a> = EspHttpWsAsyncReceiver where U: 'a;
1944
1945    //     async fn accept(&self) -> Result<(Self::Sender<'_>, Self::Receiver<'_>), Self::Error> {
1946    //         self.await
1947    //     }
1948    // }
1949
1950    // #[allow(clippy::type_complexity)]
1951    // pub struct EspHttpWsProcessor<const N: usize> {
1952    //     connections: alloc::vec::Vec<ConnectionState>,
1953    //     frame_data_buf: [u8; N],
1954    //     accept: Arc<Mutex<SharedAcceptorState>>,
1955    //     condvar: Arc<Condvar>,
1956    // }
1957
1958    // impl<const N: usize> EspHttpWsProcessor<N> {
1959    //     pub fn new<U>(unblocker: U) -> (Self, EspHttpWsAsyncAcceptor<U>) {
1960    //         let this = Self {
1961    //             connections: alloc::vec::Vec::new(),
1962    //             frame_data_buf: [0_u8; N],
1963    //             accept: Arc::new(Mutex::new(SharedAcceptorState {
1964    //                 waker: None,
1965    //                 data: None,
1966    //             })),
1967    //             condvar: Arc::new(Condvar::new()),
1968    //         };
1969
1970    //         let acceptor = EspHttpWsAsyncAcceptor {
1971    //             unblocker,
1972    //             accept: this.accept.clone(),
1973    //             condvar: this.condvar.clone(),
1974    //         };
1975
1976    //         (this, acceptor)
1977    //     }
1978
1979    //     pub fn process(&mut self, connection: &mut EspHttpWsConnection) -> Result<(), EspError> {
1980    //         if connection.is_new() {
1981    //             let session = connection.session();
1982
1983    //             info!("New WS connection {:?}", session);
1984
1985    //             self.process_accept(session, connection)?;
1986    //         } else if connection.is_closed() {
1987    //             let session = connection.session();
1988
1989    //             if let Some(index) = self
1990    //                 .connections
1991    //                 .iter()
1992    //                 .enumerate()
1993    //                 .find_map(|(index, conn)| (conn.session == session).then_some(index))
1994    //             {
1995    //                 let conn = self.connections.swap_remove(index);
1996
1997    //                 Self::process_receive_close(&conn.receiver_state);
1998    //                 info!("Closed WS connection {:?}", session);
1999    //             }
2000    //         } else {
2001    //             let session = connection.session();
2002    //             let (frame_type, len) = connection.recv(&mut self.frame_data_buf)?;
2003
2004    //             debug!(
2005    //                 "Incoming data (frame_type={:?}, frame_len={}) from WS connection {:?}",
2006    //                 frame_type, len, session
2007    //             );
2008
2009    //             if let Some(connection) = self
2010    //                 .connections
2011    //                 .iter()
2012    //                 .find(|connection| connection.session == session)
2013    //             {
2014    //                 self.process_receive(&connection.receiver_state, frame_type, len)
2015    //             }
2016    //         }
2017
2018    //         Ok(())
2019    //     }
2020
2021    //     fn process_accept(
2022    //         &mut self,
2023    //         session: ffi::c_int,
2024    //         sender: &EspHttpWsConnection,
2025    //     ) -> Result<(), EspError> {
2026    //         let receiver_state = Arc::new(Mutex::new(SharedReceiverState {
2027    //             waker: None,
2028    //             data: ReceiverData::None,
2029    //         }));
2030
2031    //         let state = ConnectionState {
2032    //             session,
2033    //             receiver_state: receiver_state.clone(),
2034    //         };
2035
2036    //         self.connections.push(state);
2037
2038    //         let sender = sender.create_detached_sender()?;
2039
2040    //         let mut accept = self.accept.lock();
2041
2042    //         accept.data = Some(Some((receiver_state, sender)));
2043
2044    //         if let Some(waker) = accept.waker.take() {
2045    //             waker.wake();
2046    //         }
2047
2048    //         while accept.data.is_some() {
2049    //             accept = self.condvar.wait(accept);
2050    //         }
2051
2052    //         Ok(())
2053    //     }
2054
2055    //     fn process_receive(
2056    //         &self,
2057    //         state: &Mutex<SharedReceiverState>,
2058    //         frame_type: FrameType,
2059    //         len: usize,
2060    //     ) {
2061    //         let mut shared = state.lock();
2062
2063    //         shared.data = ReceiverData::Metadata((frame_type, len));
2064
2065    //         if let Some(waker) = shared.waker.take() {
2066    //             waker.wake();
2067    //         }
2068
2069    //         loop {
2070    //             if let ReceiverData::Data(buf) = &shared.data {
2071    //                 unsafe { slice::from_raw_parts_mut(*buf, len) }
2072    //                     .copy_from_slice(&self.frame_data_buf[..len]);
2073    //                 shared.data = ReceiverData::DataCopied;
2074    //                 self.condvar.notify_all();
2075
2076    //                 break;
2077    //             }
2078
2079    //             shared = self.condvar.wait(shared);
2080    //         }
2081
2082    //         while !matches!(shared.data, ReceiverData::None) {
2083    //             shared = self.condvar.wait(shared);
2084    //         }
2085    //     }
2086
2087    //     fn process_accept_close(&mut self) {
2088    //         let mut accept = self.accept.lock();
2089
2090    //         accept.data = Some(None);
2091
2092    //         if let Some(waker) = accept.waker.take() {
2093    //             waker.wake();
2094    //         }
2095    //     }
2096
2097    //     fn process_receive_close(state: &Mutex<SharedReceiverState>) {
2098    //         let mut shared = state.lock();
2099
2100    //         shared.data = ReceiverData::Closed;
2101
2102    //         if let Some(waker) = shared.waker.take() {
2103    //             waker.wake();
2104    //         }
2105    //     }
2106    // }
2107
2108    // impl<const N: usize> Drop for EspHttpWsProcessor<N> {
2109    //     fn drop(&mut self) {
2110    //         self.process_accept_close();
2111    //     }
2112    // }
2113}