DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
dwserver_internal.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file dwserver_internal.h
6 * @brief Library-private declarations shared between dwserver.cpp and the src/server/*.cpp
7 * request-handler translation units it is split into (WebDAV, file serving, ...).
8 *
9 * These are NOT part of the public API - they are the handful of dwserver.cpp file-scope helpers
10 * that a split-out handler still needs, promoted from `static` to external linkage so the pieces
11 * link together. Everything else a handler needs is either a public DetWebServer method (declared
12 * in dwserver.h) or already an extern in the transport headers (e.g. conn_pool in tcp.h).
13 */
14
15#ifndef DETERMINISTICESPASYNCWEBSERVER_SERVER_INTERNAL_H
16#define DETERMINISTICESPASYNCWEBSERVER_SERVER_INTERNAL_H
17
18#include "dwserver.h"
19#include <time.h>
20
21/** @brief Reason phrase for an HTTP status code (e.g. 404 -> "Not Found"). */
22const char *status_text(int code);
23
24/** @brief Initialize the common fields (path, flags) of a route-table entry from its pattern. */
25void fill_route_base(Route *r, const char *path);
26
27/** @brief Format @p t as an RFC 1123 GMT date into @p out (cap bytes); @p out is emptied for t <= 0. */
28void http_rfc1123(time_t t, char *out, size_t cap);
29
30/** @brief True if the request in slot @p slot_id used the HEAD method (send headers, no body). */
31bool req_is_head(uint8_t slot_id);
32
33/** @brief Whole-path regex match (anchored both ends; bounded by RE_MAX_STEPS, fails closed).
34 * Defined in server/regex.cpp, called by the route dispatcher for `on_regex()` routes. */
35bool regex_match(const char *pattern, const char *path);
36
37// ---------------------------------------------------------------------------
38// Outbound-transfer continuations (owned by dwserver.cpp, shared with the split handlers)
39// ---------------------------------------------------------------------------
40
41#if DETWS_ENABLE_FILE_SERVING
42// Cross-loop file-send continuation. A file response larger than the TCP send
43// buffer cannot be blasted out in one dispatch (tcp_write returns ERR_MEM once the
44// window fills and the rest would be dropped). Instead serve_file_internal sends
45// the headers, opens the file, and hands it to this per-slot state; file_send_pump
46// pages out at most det_conn_sndbuf() bytes per worker loop and resumes on the next
47// loop (woken promptly by the sent callback) as the window drains - no truncation,
48// no blocking the worker. One transfer per slot at a time.
49struct FileSend
50{
51 fs::File file; ///< open source file (held across loops).
52 size_t off; ///< absolute file offset of the next byte to send.
53 size_t remaining; ///< body bytes still to send.
54 int status; ///< response status (200 / 206) for note_response.
55 int total; ///< total body length, for the access log.
56 bool keep; ///< keep-alive vs close at completion.
57 bool active; ///< a transfer is in progress on this slot.
58};
59#endif
60
61// Per-slot chunked-send continuation. Mirrors FileSend but pulls body pieces from
62// a ChunkSource generator and adds the HTTP chunk framing; paged across loops.
64{
65 ChunkSource source; ///< body generator (active==false means none).
66 void *ctx; ///< caller state passed to source (must outlive the send).
67 int status; ///< response status, for note_response.
68 int total; ///< body bytes emitted so far (excludes framing).
69 bool keep; ///< keep-alive vs close at completion.
70 bool active; ///< a chunked response is in progress on this slot.
71 bool raw; ///< HTTP/1.0 client: stream the body unframed, close-delimited (no chunk wrapping).
72};
73
74// All per-slot outbound-transfer continuations, owned by one instance: the cross-loop file-send
75// state (when file serving is enabled) and the chunked-send state. Grouped so it is one named
76// owner. Defined once in dwserver.cpp; the file_serving / chunked handler TUs reference it.
77struct SendCtx
78{
79#if DETWS_ENABLE_FILE_SERVING
80 FileSend file[MAX_CONNS];
81#endif
83};
84extern SendCtx s_send;
85
86// ---------------------------------------------------------------------------
87// WebSocket / SSE upgrade entry points (defined in server/websocket_sse.cpp, called
88// by the route dispatcher in dwserver.cpp when a matched route is a WS/SSE endpoint).
89// ---------------------------------------------------------------------------
90
91#if DETWS_ENABLE_WEBSOCKET
92/** @brief Perform the RFC 6455 101 handshake and hand the slot to the WS frame parser. */
93bool ws_do_upgrade(uint8_t slot_id, HttpReq *req, WsConnectHandler on_connect);
94
95/** @brief Reject an unsupported Sec-WebSocket-Version with a 426 (RFC 6455 4.2.1) and close. */
96void ws_send_version_required(uint8_t slot_id);
97#endif
98
99#if DETWS_ENABLE_SSE
100/** @brief Send the SSE 200 headers and promote the slot to server-sent-events mode. */
101bool sse_do_upgrade(uint8_t slot_id, HttpReq *req, SseConnectHandler on_connect);
102#endif
103
104#endif // DETERMINISTICESPASYNCWEBSERVER_SERVER_INTERNAL_H
#define MAX_CONNS
Maximum simultaneous TCP connections (fixed static pool; ~3.95 KB of internal RAM per slot).
Layer 7 (Application) - public HTTP routing API.
size_t(* ChunkSource)(uint8_t *buf, size_t cap, void *ctx)
Source callback that produces a chunked response body incrementally.
Definition dwserver.h:310
void fill_route_base(Route *r, const char *path)
Initialize the common fields (path, flags) of a route-table entry from its pattern.
Definition dwserver.cpp:747
const char * status_text(int code)
Reason phrase for an HTTP status code (e.g. 404 -> "Not Found").
Definition dwserver.cpp:112
void http_rfc1123(time_t t, char *out, size_t cap)
Format t as an RFC 1123 GMT date into out (cap bytes); out is emptied for t <= 0.
SendCtx s_send
Definition dwserver.cpp:97
bool req_is_head(uint8_t slot_id)
True if the request in slot slot_id used the HEAD method (send headers, no body).
bool regex_match(const char *pattern, const char *path)
Whole-path regex match (anchored both ends; bounded by RE_MAX_STEPS, fails closed)....
Definition regex.cpp:188
ChunkSource source
body generator (active==false means none).
int status
response status, for note_response.
void * ctx
caller state passed to source (must outlive the send).
bool raw
HTTP/1.0 client: stream the body unframed, close-delimited (no chunk wrapping).
bool active
a chunked response is in progress on this slot.
int total
body bytes emitted so far (excludes framing).
bool keep
keep-alive vs close at completion.
Fully-parsed HTTP/1.1 request.
Internal route entry stored in the routing table.
Definition dwserver.h:244
ChunkSend chunk[MAX_CONNS]