ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
protocore_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 protocore_internal.h
6 * @brief Library-private declarations shared between protocore.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 protocore.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 PC method (declared
12 * in protocore.h) or already an extern in the transport headers (e.g. conn_pool in tcp.h).
13 */
14
15#ifndef PROTOCORE_INTERNAL_H
16#define PROTOCORE_INTERNAL_H
17
18#include "protocore.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/**
25 * @brief The fixed reply sent when a response's own headers will not fit RESP_HDR_BUF_SIZE.
26 *
27 * A header block cut short has no terminating CRLF, so the peer keeps reading the body as headers
28 * and the connection desynchronizes - which is why truncating is not an option and this always-
29 * fitting reply goes out instead. Connection: close, because the request is not recoverable.
30 */
31extern const char PC_RESP_HDR_OVERFLOW[];
32
33/** @brief Length of PC_RESP_HDR_OVERFLOW, taken with sizeof where the array bound is still visible. */
34extern const size_t PC_RESP_HDR_OVERFLOW_LEN;
35
36/** @brief Initialize the common fields (path, flags) of a route-table entry from its pattern. */
37void fill_route_base(Route *r, const char *path);
38
39/** @brief Format @p t as an RFC 1123 GMT date into @p out (cap bytes); @p out is emptied for t <= 0. */
40void http_rfc1123(time_t t, char *out, size_t cap);
41
42/** @brief True if the request in slot @p slot_id used the HEAD method (send headers, no body). */
43bool req_is_head(uint8_t slot_id);
44
45/** @brief Whole-path regex match (anchored both ends; bounded by RE_MAX_STEPS, fails closed).
46 * Defined in server/regex.cpp, called by the route dispatcher for `on_regex()` routes. */
47bool regex_match(const char *pattern, const char *path);
48
49// ---------------------------------------------------------------------------
50// Outbound-transfer continuations (owned by protocore.cpp, shared with the split handlers)
51// ---------------------------------------------------------------------------
52
53#if PC_ENABLE_FILE_SERVING
54// Cross-loop file-send continuation. A file response larger than the TCP send
55// buffer cannot be blasted out in one dispatch (tcp_write returns ERR_MEM once the
56// window fills and the rest would be dropped). Instead serve_file_internal sends
57// the headers, opens the file, and hands it to this per-slot state; file_send_pump
58// pages out at most pc_conn_sndbuf() bytes per worker loop and resumes on the next
59// loop (woken promptly by the sent callback) as the window drains - no truncation,
60// no blocking the worker. One transfer per slot at a time.
61struct FileSend
62{
63 fs::File file; ///< open source file (held across loops).
64 size_t off; ///< absolute file offset of the next byte to send.
65 size_t remaining; ///< body bytes still to send.
66 int status; ///< response status (200 / 206) for note_response.
67 int total; ///< total body length, for the access log.
68 bool keep; ///< keep-alive vs close at completion.
69 bool active; ///< a transfer is in progress on this slot.
70};
71#endif
72
73// Per-slot chunked-send continuation. Mirrors FileSend but pulls body pieces from
74// a ChunkSource generator and adds the HTTP chunk framing; paged across loops.
76{
77 ChunkSource source; ///< body generator (active==false means none).
78 void *ctx; ///< caller state passed to source (must outlive the send).
79 int status; ///< response status, for note_response.
80 int total; ///< body bytes emitted so far (excludes framing).
81 bool keep; ///< keep-alive vs close at completion.
82 bool active; ///< a chunked response is in progress on this slot.
83 bool raw; ///< HTTP/1.0 client: stream the body unframed, close-delimited (no chunk wrapping).
84};
85
86// All per-slot outbound-transfer continuations, owned by one instance: the cross-loop file-send
87// state (when file serving is enabled) and the chunked-send state. Grouped so it is one named
88// owner. Defined once in protocore.cpp; the file_serving / chunked handler TUs reference it.
89struct SendCtx
90{
91#if PC_ENABLE_FILE_SERVING
92 FileSend file[MAX_CONNS];
93#endif
95};
96extern SendCtx s_send;
97
98// ---------------------------------------------------------------------------
99// WebSocket / SSE upgrade entry points (defined in server/websocket_sse.cpp, called
100// by the route dispatcher in protocore.cpp when a matched route is a WS/SSE endpoint).
101// ---------------------------------------------------------------------------
102
103#if PC_ENABLE_WEBSOCKET
104/** @brief Perform the RFC 6455 101 handshake and hand the slot to the WS frame parser. */
105bool ws_do_upgrade(uint8_t slot_id, HttpReq *req, WsConnectHandler on_connect);
106
107/** @brief Reject an unsupported Sec-WebSocket-Version with a 426 (RFC 6455 4.2.1) and close. */
108void ws_send_version_required(uint8_t slot_id);
109#endif
110
111#if PC_ENABLE_SSE
112/** @brief Send the SSE 200 headers and promote the slot to server-sent-events mode. */
113bool pc_sse_do_upgrade(uint8_t slot_id, HttpReq *req, SseConnectHandler on_connect);
114#endif
115
116#endif // PROTOCORE_INTERNAL_H
#define MAX_CONNS
Definition c2_defaults.h:47
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 protocore.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.
const char * status_text(int code)
Reason phrase for an HTTP status code (e.g. 404 -> "Not Found").
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
const size_t PC_RESP_HDR_OVERFLOW_LEN
Length of PC_RESP_HDR_OVERFLOW, taken with sizeof where the array bound is still visible.
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:226
const char PC_RESP_HDR_OVERFLOW[]
The fixed reply sent when a response's own headers will not fit RESP_HDR_BUF_SIZE.
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 protocore.h:244
ChunkSend chunk[MAX_CONNS]