Seregon/zftpd

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

C/11.0 KB/No license
include/http_response.h
zftpd / include / http_response.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 * @file http_response.h
26 * @brief HTTP response builder
27 *
28 * STATUS CODES:
29 * 2xx Success (200, 201, 204)
30 * 3xx Redirection (301, 304)
31 * 4xx Client error (400, 403, 404, 405)
32 * 5xx Server error (500)
33 */
34 
35#ifndef HTTP_RESPONSE_H
36#define HTTP_RESPONSE_H
37 
38#include "http_config.h"
39#include <stddef.h>
40#include <sys/types.h>
41 
42/*===========================================================================*
43 * HTTP STATUS CODES
44 *===========================================================================*/
45 
46typedef enum {
47 /* 2xx ── Success */
48 HTTP_STATUS_200_OK = 200,
49 HTTP_STATUS_201_CREATED = 201,
50 HTTP_STATUS_204_NO_CONTENT = 204,
51 
52 /* 3xx ── Redirection */
53 HTTP_STATUS_301_MOVED = 301,
54 HTTP_STATUS_304_NOT_MODIFIED = 304,
55 
56 /* 4xx ── Client Error */
57 HTTP_STATUS_400_BAD_REQUEST = 400,
58 HTTP_STATUS_403_FORBIDDEN = 403,
59 HTTP_STATUS_404_NOT_FOUND = 404,
60 HTTP_STATUS_405_METHOD_NOT_ALLOWED = 405,
61 HTTP_STATUS_409_CONFLICT = 409,
62 
63 /* 5xx ── Server Error */
64 HTTP_STATUS_500_INTERNAL_ERROR = 500,
65} http_status_t;
66 
67/*===========================================================================*
68 * RESPONSE BUFFER
69 *===========================================================================*/
70 
71typedef struct {
72 char data[HTTP_RESPONSE_BUFFER_SIZE];
73 size_t used;
74 
75 /* In-memory body streaming (for large embedded static assets) */
76 const void *mem_body; /**< Pointer to body bytes (NULL = not used) */
77 size_t mem_length; /**< Total bytes to send */
78 size_t mem_sent; /**< Bytes already sent */
79 int mem_body_owned; /**< 1 = malloc'd, destroy() must free it */
80 
81 /* In-memory segmented body streaming (for injected HTML) */
82 const void *mem_segs[3]; /**< Segment pointers */
83 size_t mem_lens[3]; /**< Segment lengths */
84 size_t mem_seg_count; /**< 0 = disabled, otherwise 1..3 */
85 size_t mem_seg_index; /**< Current segment index */
86 size_t mem_seg_sent; /**< Bytes sent in current segment */
87 char mem_inline[160]; /**< Inline storage for small injected data */
88 
89 /* sendfile() support for zero-copy file downloads */
90 int sendfile_fd; /**< File fd (-1 = not used) */
91 off_t sendfile_offset; /**< Current offset in file */
92 size_t sendfile_count; /**< Remaining bytes to send */
93 int sendfile_safe; /**< 1 = FS supports sendfile(2) safely;
94 * 0 = must use pread()+send() fallback.
95 *
96 * On PS5/PS4 (FreeBSD), calling sendfile(2) on
97 * certain filesystem types (exfatfs, msdosfs,
98 * nullfs, pfsmnt, pfs) dereferences a null
99 * function pointer inside the kernel vnode pager
100 * and causes an IMMEDIATE KERNEL PANIC — errno
101 * is never set, the process never returns.
102 * The flag is checked in http_server.c BEFORE
103 * the first call to pal_sendfile(). */
104 
105 /* Chunked directory streaming (for /api/list) */
106 void *stream_dir; /**< DIR* — NULL = not streaming */
107 char stream_path[1024]; /**< Base path for stat() calls */
108} http_response_t;
109 
110/*===========================================================================*
111 * PUBLIC API
112 *===========================================================================*/
113 
114http_response_t *http_response_create(http_status_t status);
115int http_response_add_header(http_response_t *resp, const char *name,
116 const char *value);
117int http_response_set_body(http_response_t *resp, const void *body,
118 size_t length);
119int http_response_set_body_owned(http_response_t *resp, void *body,
120 size_t length);
121int http_response_set_body_ref(http_response_t *resp, const void *body,
122 size_t length);
123int http_response_set_body_splice(http_response_t *resp, const void *prefix,
124 size_t prefix_len, const void *insert,
125 size_t insert_len, const void *suffix,
126 size_t suffix_len);
127int http_response_append_raw(http_response_t *resp, const void *data,
128 size_t length);
129int http_response_finalize(http_response_t *resp);
130void http_response_destroy(http_response_t *resp);
131 
132#endif /* HTTP_RESPONSE_H */
133