Seregon/zftpd

Zero-copy FTP/HTTP Daemon compatible with all POSIX systems

C/11.0 KB/No license
include/http_config.h
zftpd / include / http_config.h
1/*
2MIT License
3 
4Copyright (c) 2026 Seregon
5 
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12 
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15 
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24 
25/**
26 * @file http_config.h
27 * @brief HTTP server configuration
28 */
29 
30#ifndef HTTP_CONFIG_H
31#define HTTP_CONFIG_H
32 
33#include <stdint.h>
34 
35/* Compile-time feature toggle */
36#ifndef ENABLE_ZHTTPD
37#define ENABLE_ZHTTPD 1
38#endif
39 
40#ifndef ENABLE_HTTP_GZIP
41#define ENABLE_HTTP_GZIP 0
42#endif
43 
44#ifndef HTTP_DEBUG_LOG_HEADERS
45#define HTTP_DEBUG_LOG_HEADERS 0
46#endif
47 
48/*---------------------------------------------------------------------------*
49 * Web root directory — static files are served from this path.
50 *
51 * When set, serve_static() reads files from disk instead of the embedded
52 * http_resources.c blob. This decouples the web UI from the payload binary,
53 * making development faster and the payload ~10 MB smaller.
54 *
55 * On PS5: /data/zftpd/web/
56 * On desktop (dev): ./web/ (relative to cwd)
57 *---------------------------------------------------------------------------*/
58#ifndef HTTP_WEB_ROOT
59#if defined(PS5) || defined(PLATFORM_PS5) || defined(PS4) || defined(PLATFORM_PS4)
60#define HTTP_WEB_ROOT "/data/zftpd/web/"
61#else
62#define HTTP_WEB_ROOT "web/"
63#endif
64#endif
65 
66/* Server configuration */
67#define HTTP_DEFAULT_PORT 8888
68#define HTTP_MAX_CONNECTIONS 100
69#define HTTP_REQUEST_TIMEOUT 30
70#define HTTP_KEEPALIVE_TIMEOUT 60
71 
72/* Buffer sizes */
73#define HTTP_REQUEST_BUFFER_SIZE 8192
74#define HTTP_RESPONSE_BUFFER_SIZE 8192
75#define HTTP_URI_MAX_LENGTH 2048
76#define HTTP_HEADER_MAX_COUNT 32
77#define HTTP_HEADER_LINE_MAX 1024
78 
79/*
80 * File transfer chunk size for sendfile() in /api/download.
81 *
82 * PS5 REGRESSION NOTE:
83 * PS5's modified FreeBSD kernel triggers an internal buffer limit with
84 * sendfile() chunks >= 1 MB, returning EAGAIN (sbytes = 0) even on
85 * nominally-blocking sockets. Each EAGAIN costs a usleep(1 ms) yield
86 * (to avoid busy-spinning). At 1 MB/chunk: 1.2 GB / 1 MB × 1 ms =
87 * ~1.2 s of extra sleep latency per download — the observed regression
88 * ("previously downloaded 1.2 GB immediately").
89 *
90 * 512 KB chunks stay well below the 1 MB trigger threshold, eliminating
91 * the EAGAIN storms while keeping syscall count reasonable (2× increase
92 * vs 1 MB, negligible vs I/O latency).
93 */
94#define HTTP_SENDFILE_CHUNK_SIZE (512 * 1024)
95 
96/* Thread stack size (bytes) */
97#ifndef HTTP_THREAD_STACK_SIZE
98#define HTTP_THREAD_STACK_SIZE (512U * 1024U)
99#endif
100 
101/* CSRF token length in hex characters (32 hex = 16 random bytes) */
102#define HTTP_CSRF_TOKEN_LENGTH 32
103 
104/*---------------------------------------------------------------------------*
105 * Upload feature toggle (disabled by default for security)
106 *---------------------------------------------------------------------------*/
107#ifndef ENABLE_WEB_UPLOAD
108#define ENABLE_WEB_UPLOAD 0
109#endif
110 
111/*---------------------------------------------------------------------------*
112 * Upload streaming performance tuning
113 *
114 * HTTP_UPLOAD_CHUNK_SIZE
115 * Heap-allocated read buffer used exclusively while an upload is active.
116 * Each event-loop iteration drains up to this many bytes from the socket.
117 *
118 * Rationale:
119 * The connection's header buffer (HTTP_REQUEST_BUFFER_SIZE = 8 KB) is
120 * reused during streaming, capping each read() at 8 KB. At 113 MB/s
121 * that requires ~13 800 read() + kqueue round-trips per second — well
122 * beyond what a single-threaded event loop can sustain.
123 *
124 * 256 KB reduces the required syscall rate to ~440/s at 113 MB/s,
125 * comfortably within budget while keeping per-upload heap overhead low.
126 * The buffer is allocated on upload start and freed on completion, so
127 * idle connections pay no memory cost.
128 *
129 * HTTP_UPLOAD_RCVBUF_SIZE
130 * SO_RCVBUF hint set on each accepted client socket. A larger kernel
131 * receive buffer absorbs TCP bursts between event-loop wakeups and keeps
132 * the sender's congestion window open. 2 MB is sufficient for RTTs up
133 * to ~140 µs at 113 MB/s (BDP = 113e6 * 140e-6 ≈ 15 KB; 2 MB is 133×
134 * the BDP — intentionally oversized so the kernel never stalls).
135 *
136 * IMPORTANT: This is a hint only. The kernel caps it at
137 * net.core.rmem_max (Linux) or kern.ipc.maxsockbuf (FreeBSD/PS5).
138 * Setting it higher than the system maximum is silently ignored.
139 *---------------------------------------------------------------------------*/
140#ifndef HTTP_UPLOAD_CHUNK_SIZE
141#define HTTP_UPLOAD_CHUNK_SIZE (512U * 1024U) /* 512 KB per active upload */
142#endif
143 
144#ifndef HTTP_UPLOAD_RCVBUF_SIZE
145#define HTTP_UPLOAD_RCVBUF_SIZE (2U * 1024U * 1024U) /* 2 MB SO_RCVBUF hint */
146#endif
147 
148/*---------------------------------------------------------------------------*
149 * Download pread() chunk size (PATH B — pread + pal_send_all)
150 *
151 * Used when sendfile() is unsafe (PS5/PS4 PFS/exFAT filesystems).
152 * Larger chunks mean fewer pread()+send_all() round-trips per MB.
153 * 2 MB halves the syscall count vs the previous 512 KB while staying
154 * well within the event-loop thread's heap budget.
155 *---------------------------------------------------------------------------*/
156#ifndef HTTP_DOWNLOAD_PREAD_CHUNK
157#define HTTP_DOWNLOAD_PREAD_CHUNK (2U * 1024U * 1024U) /* 2 MB */
158#endif
159 
160/*---------------------------------------------------------------------------*
161 * HTTP client send buffer (SO_SNDBUF) — download throughput on PS5/PS4
162 *
163 * OrbisOS (PS5/PS4) clamps TCP send-buffer auto-tuning to a system
164 * maximum that is lower than what a GbE LAN download needs. Without
165 * an explicit SO_SNDBUF the accepted socket keeps the kernel default
166 * (~256 KB on tested firmwares), forcing pal_send_all() to block as
167 * soon as the buffer fills and limiting throughput to ~400 Mbps.
168 *
169 * Setting 4 MB matches FTP_TCP_DATA_SNDBUF (the same fix applied to
170 * FTP data sockets) and allows the TCP pipeline to stay full at
171 * 1 Gbps LAN RTTs (0.1–1 ms), recovering the missing 300+ Mbps.
172 *
173 * On other platforms SO_SNDBUF is left to kernel auto-tuning (set to 0
174 * here so the caller can skip the setsockopt() call entirely).
175 *---------------------------------------------------------------------------*/
176#ifndef HTTP_SNDBUF_SIZE
177#if defined(PS5) || defined(PLATFORM_PS5) || defined(PS4) || defined(PLATFORM_PS4)
178#define HTTP_SNDBUF_SIZE (4U * 1024U * 1024U) /* 4 MB — bypass OrbisOS clamp */
179#else
180#define HTTP_SNDBUF_SIZE 0U /* 0 = leave kernel auto-tuning active */
181#endif
182#endif
183 
184#endif /* HTTP_CONFIG_H */
185