@velox0/cerver 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/runtime/cerver.h CHANGED
@@ -17,25 +17,40 @@
17
17
  /* Limits */
18
18
  /* ------------------------------------------------------------------ */
19
19
 
20
- #define CERVER_MAX_HEADERS 64
21
- #define CERVER_MAX_PARAMS 16
22
- #define CERVER_MAX_QUERY 32
23
- #define CERVER_MAX_PATH 2048
24
- #define CERVER_MAX_HEADER_VAL 4096
25
- #define CERVER_READ_BUF 8192
26
- #define CERVER_READ_BUF_MAX (1 << 20) /* 1 MB hard limit */
27
- #define CERVER_MAX_ROUTES 256
28
-
29
- #define CERVER_THREAD_POOL_DEFAULT 4
30
- #define CERVER_TASK_QUEUE_SIZE 256
20
+ #define CERVER_MAX_HEADERS 64
21
+ #define CERVER_MAX_PARAMS 16
22
+ #define CERVER_MAX_QUERY 32
23
+ #define CERVER_MAX_PATH 2048
24
+ #define CERVER_MAX_HEADER_VAL 4096
25
+ #define CERVER_READ_BUF 8192
26
+ #define CERVER_READ_BUF_MAX (1 << 20) /* 1 MB hard limit */
27
+ #define CERVER_MAX_ROUTES 256
28
+
29
+ /* Keep-alive settings */
30
+ #define CERVER_KEEPALIVE_MAX 2000000000 /* max requests per connection */
31
+ #define CERVER_KEEPALIVE_TIMEOUT 5 /* seconds idle between requests */
32
+ #define CERVER_KEEPALIVE_MAX 2000000000 /* max requests per connection */
33
+ #define CERVER_KEEPALIVE_TIMEOUT 5 /* seconds idle between requests */
34
+
35
+ /* Event loop tuning */
36
+ #define CERVER_MAX_EVENTS 256
37
+ #define CERVER_LISTEN_BACKLOG 4096
38
+
39
+ /* Worker architecture */
40
+ #define CERVER_THREAD_POOL_DEFAULT 4
41
+ #define CERVER_TASK_QUEUE_SIZE 1024
42
+
43
+ /* Stat cache for filesystem serving */
44
+ #define CERVER_STAT_CACHE_SIZE 256
45
+ #define CERVER_STAT_CACHE_TTL 60 /* seconds */
31
46
 
32
47
  /* ------------------------------------------------------------------ */
33
48
  /* Key-value pair (used for headers, query params, route params) */
34
49
  /* ------------------------------------------------------------------ */
35
50
 
36
51
  typedef struct {
37
- const char *key;
38
- const char *value;
52
+ const char* key;
53
+ const char* value;
39
54
  } cerver_kv_t;
40
55
 
41
56
  /* ------------------------------------------------------------------ */
@@ -43,34 +58,34 @@ typedef struct {
43
58
  /* ------------------------------------------------------------------ */
44
59
 
45
60
  typedef struct {
46
- /* HTTP method: "GET", "POST", etc. */
47
- char method[16];
61
+ /* HTTP method: "GET", "POST", etc. */
62
+ char method[16];
48
63
 
49
- /* Decoded path (no query string) */
50
- char path[CERVER_MAX_PATH];
64
+ /* Decoded path (no query string) */
65
+ char path[CERVER_MAX_PATH];
51
66
 
52
- /* Raw query string (after '?') */
53
- char query_string[CERVER_MAX_PATH];
67
+ /* Raw query string (after '?') */
68
+ char query_string[CERVER_MAX_PATH];
54
69
 
55
- /* Parsed query parameters */
56
- cerver_kv_t query[CERVER_MAX_QUERY];
57
- int query_count;
70
+ /* Parsed query parameters */
71
+ cerver_kv_t query[CERVER_MAX_QUERY];
72
+ int query_count;
58
73
 
59
- /* Route parameters (from dynamic segments like :key) */
60
- cerver_kv_t params[CERVER_MAX_PARAMS];
61
- int params_count;
74
+ /* Route parameters (from dynamic segments like :key) */
75
+ cerver_kv_t params[CERVER_MAX_PARAMS];
76
+ int params_count;
62
77
 
63
- /* Request headers */
64
- cerver_kv_t headers[CERVER_MAX_HEADERS];
65
- int header_count;
78
+ /* Request headers */
79
+ cerver_kv_t headers[CERVER_MAX_HEADERS];
80
+ int header_count;
66
81
 
67
- /* Request body (for POST) */
68
- const char *body;
69
- size_t body_len;
82
+ /* Request body (for POST) */
83
+ const char* body;
84
+ size_t body_len;
70
85
 
71
- /* Internal: raw buffer ownership */
72
- char *_raw_buf;
73
- size_t _raw_len;
86
+ /* Internal: raw buffer ownership (NULL if in-place parsing used) */
87
+ char* _raw_buf;
88
+ size_t _raw_len;
74
89
  } cerver_request_t;
75
90
 
76
91
  /* ------------------------------------------------------------------ */
@@ -78,47 +93,53 @@ typedef struct {
78
93
  /* ------------------------------------------------------------------ */
79
94
 
80
95
  typedef struct {
81
- int status;
82
- const char *content_type;
96
+ int status;
97
+ const char* content_type;
98
+
99
+ /* Response body — can be heap-allocated or static */
100
+ const char* body;
101
+ size_t body_len;
83
102
 
84
- /* Response body — can be heap-allocated or static */
85
- const char *body;
86
- size_t body_len;
103
+ /* Extra headers */
104
+ cerver_kv_t headers[CERVER_MAX_HEADERS];
105
+ int header_count;
87
106
 
88
- /* Extra headers */
89
- cerver_kv_t headers[CERVER_MAX_HEADERS];
90
- int header_count;
107
+ /* Internal flag: was body malloc'd? */
108
+ int _body_owned;
91
109
 
92
- /* Internal flag: was body malloc'd? */
93
- int _body_owned;
110
+ /* Keep-alive control: set to 1 to force close after response */
111
+ int _force_close;
94
112
  } cerver_response_t;
95
113
 
96
114
  /* Response helpers — called by generated handler code */
97
- void cerver_res_text(cerver_response_t *res, int status, const char *text);
98
- void cerver_res_json(cerver_response_t *res, int status, const char *json);
99
- void cerver_res_html(cerver_response_t *res, int status, const char *html);
100
- void cerver_res_file(cerver_response_t *res, int status, const char *mime,
101
- const unsigned char *data, size_t len);
102
- void cerver_res_header(cerver_response_t *res, const char *key, const char *val);
115
+ void cerver_res_text(cerver_response_t* res, int status, const char* text);
116
+ void cerver_res_json(cerver_response_t* res, int status, const char* json);
117
+ void cerver_res_html(cerver_response_t* res, int status, const char* html);
118
+ void cerver_res_file(cerver_response_t* res, int status, const char* mime,
119
+ const unsigned char* data, size_t len);
120
+ void cerver_res_header(cerver_response_t* res, const char* key, const char* val);
103
121
 
104
122
  /* ------------------------------------------------------------------ */
105
123
  /* Request helpers */
106
124
  /* ------------------------------------------------------------------ */
107
125
 
108
- const char *cerver_req_param(const cerver_request_t *req, const char *key);
109
- const char *cerver_req_query(const cerver_request_t *req, const char *key);
110
- const char *cerver_req_header(const cerver_request_t *req, const char *key);
126
+ const char* cerver_req_param(const cerver_request_t* req, const char* key);
127
+ const char* cerver_req_query(const cerver_request_t* req, const char* key);
128
+ const char* cerver_req_header(const cerver_request_t* req, const char* key);
129
+
130
+ /* Check if client wants to close after this request */
131
+ int cerver_req_wants_close(const cerver_request_t* req);
111
132
 
112
133
  /* ------------------------------------------------------------------ */
113
134
  /* Route definition */
114
135
  /* ------------------------------------------------------------------ */
115
136
 
116
- typedef void (*cerver_handler_fn)(cerver_request_t *req, cerver_response_t *res);
137
+ typedef void (*cerver_handler_fn)(cerver_request_t* req, cerver_response_t* res);
117
138
 
118
139
  typedef struct {
119
- const char *method; /* "GET", "POST" */
120
- const char *pattern; /* "/", "/art/:key", "/api/projects" */
121
- cerver_handler_fn handler;
140
+ const char* method; /* "GET", "POST" */
141
+ const char* pattern; /* "/", "/art/:key", "/api/projects" */
142
+ cerver_handler_fn handler;
122
143
  } cerver_route_t;
123
144
 
124
145
  /* ------------------------------------------------------------------ */
@@ -126,81 +147,131 @@ typedef struct {
126
147
  /* ------------------------------------------------------------------ */
127
148
 
128
149
  typedef struct {
129
- const char *path; /* e.g. "/index.html" */
130
- const char *mime_type; /* e.g. "text/html" */
131
- const unsigned char *data;
132
- size_t data_len;
133
-
134
- /* Pre-compressed variants (NULL if not available) */
135
- const unsigned char *data_gz;
136
- size_t data_gz_len;
137
- const unsigned char *data_br;
138
- size_t data_br_len;
150
+ const char* path; /* e.g. "/index.html" */
151
+ const char* mime_type; /* e.g. "text/html" */
152
+ const unsigned char* data;
153
+ size_t data_len;
154
+
155
+ /* Pre-compressed variants (NULL if not available) */
156
+ const unsigned char* data_gz;
157
+ size_t data_gz_len;
158
+ const unsigned char* data_br;
159
+ size_t data_br_len;
160
+
161
+ /* Pre-computed response header (NULL if not generated) */
162
+ const char* prebuilt_header;
163
+ size_t prebuilt_header_len;
139
164
  } cerver_asset_t;
140
165
 
141
166
  /* ------------------------------------------------------------------ */
142
- /* Server */
167
+ /* Stat cache for filesystem serving */
168
+ /* ------------------------------------------------------------------ */
169
+
170
+ typedef struct {
171
+ char path[CERVER_MAX_PATH];
172
+ size_t file_size;
173
+ time_t mtime;
174
+ time_t cached_at;
175
+ int valid;
176
+ } cerver_stat_entry_t;
177
+
178
+ typedef struct {
179
+ cerver_stat_entry_t entries[CERVER_STAT_CACHE_SIZE];
180
+ pthread_mutex_t lock;
181
+ } cerver_stat_cache_t;
182
+
183
+ /* ------------------------------------------------------------------ */
184
+ /* Generated dispatch (compile-time route optimization) */
185
+ /* ------------------------------------------------------------------ */
186
+
187
+ typedef cerver_handler_fn (*cerver_dispatch_fn)(cerver_request_t* req);
188
+
143
189
  /* ------------------------------------------------------------------ */
190
+ /* Worker state (per-core event loop) */
191
+ /* ------------------------------------------------------------------ */
192
+
193
+ typedef struct cerver_server cerver_server_t;
144
194
 
145
195
  typedef struct {
146
- int port;
147
- int sock_fd;
148
- cerver_route_t *routes;
149
- int route_count;
150
- cerver_asset_t *assets;
151
- int asset_count;
152
- const char *public_dir; /* NULL if embedded mode */
153
- volatile int running;
154
-
155
- /* Thread pool */
156
- int thread_count;
157
- pthread_t *threads;
158
- int task_queue[CERVER_TASK_QUEUE_SIZE];
159
- int tq_head;
160
- int tq_tail;
161
- int tq_count;
162
- pthread_mutex_t tq_mutex;
163
- pthread_cond_t tq_cond;
164
- } cerver_server_t;
196
+ int id;
197
+ int event_fd; /* kqueue or epoll fd */
198
+ int listen_fd; /* per-worker on Linux, shared on macOS */
199
+ cerver_server_t* srv;
200
+ pthread_t thread;
201
+ } cerver_worker_t;
202
+
203
+ /* ------------------------------------------------------------------ */
204
+ /* Server */
205
+ /* ------------------------------------------------------------------ */
206
+
207
+ struct cerver_server {
208
+ int port;
209
+ int sock_fd;
210
+ cerver_route_t* routes;
211
+ int route_count;
212
+ cerver_asset_t* assets;
213
+ int asset_count;
214
+ const char* public_dir; /* NULL if embedded mode */
215
+ volatile int running;
216
+
217
+ /* Generated dispatch override (faster than generic router) */
218
+ cerver_dispatch_fn dispatch_override;
219
+
220
+ /* Stat cache for filesystem serving */
221
+ cerver_stat_cache_t stat_cache;
222
+
223
+ /* Worker pool */
224
+ int worker_count;
225
+ cerver_worker_t* workers;
226
+ };
165
227
 
166
228
  /* Server lifecycle */
167
- int cerver_init(cerver_server_t *srv, int port, int threads);
168
- int cerver_add_routes(cerver_server_t *srv, cerver_route_t *routes, int count);
169
- int cerver_set_assets(cerver_server_t *srv, cerver_asset_t *assets, int count);
170
- void cerver_set_public_dir(cerver_server_t *srv, const char *dir);
171
- int cerver_listen(cerver_server_t *srv);
172
- void cerver_shutdown(cerver_server_t *srv);
229
+ int cerver_init(cerver_server_t* srv, int port, int threads);
230
+ int cerver_add_routes(cerver_server_t* srv, cerver_route_t* routes, int count);
231
+ int cerver_set_assets(cerver_server_t* srv, cerver_asset_t* assets, int count);
232
+ void cerver_set_public_dir(cerver_server_t* srv, const char* dir);
233
+ void cerver_set_dispatch(cerver_server_t* srv, cerver_dispatch_fn fn);
234
+ int cerver_listen(cerver_server_t* srv);
235
+ void cerver_shutdown(cerver_server_t* srv);
173
236
 
174
237
  /* ------------------------------------------------------------------ */
175
238
  /* HTTP parser (internal) */
176
239
  /* ------------------------------------------------------------------ */
177
240
 
178
- int cerver_parse_request(const char *raw, size_t len, cerver_request_t *req);
241
+ int cerver_parse_request(const char* raw, size_t len, cerver_request_t* req);
179
242
 
180
243
  /* ------------------------------------------------------------------ */
181
244
  /* HTTP writer (internal) */
182
245
  /* ------------------------------------------------------------------ */
183
246
 
184
- int cerver_write_response(int fd, const cerver_response_t *res);
247
+ int cerver_write_response(int fd, const cerver_response_t* res, int keepalive);
185
248
 
186
249
  /* ------------------------------------------------------------------ */
187
250
  /* Router (internal) */
188
251
  /* ------------------------------------------------------------------ */
189
252
 
190
- int cerver_route_match(const cerver_route_t *route, cerver_request_t *req);
191
- cerver_handler_fn cerver_dispatch(cerver_server_t *srv, cerver_request_t *req);
253
+ int cerver_route_match(const cerver_route_t* route, cerver_request_t* req);
254
+ cerver_handler_fn cerver_dispatch(cerver_server_t* srv, cerver_request_t* req);
192
255
 
193
256
  /* ------------------------------------------------------------------ */
194
257
  /* MIME (internal) */
195
258
  /* ------------------------------------------------------------------ */
196
259
 
197
- const char *cerver_mime_from_path(const char *path);
260
+ const char* cerver_mime_from_path(const char* path);
198
261
 
199
262
  /* ------------------------------------------------------------------ */
200
263
  /* Static file serving (internal) */
201
264
  /* ------------------------------------------------------------------ */
202
265
 
203
- int cerver_serve_static(cerver_server_t *srv, cerver_request_t *req,
204
- cerver_response_t *res);
266
+ int cerver_serve_static(cerver_server_t* srv, cerver_request_t* req, cerver_response_t* res);
267
+
268
+ /* ------------------------------------------------------------------ */
269
+ /* Stat cache (internal) */
270
+ /* ------------------------------------------------------------------ */
271
+
272
+ void cerver_stat_cache_init(cerver_stat_cache_t* cache);
273
+ int cerver_stat_cache_lookup(cerver_stat_cache_t* cache, const char* path, size_t* file_size);
274
+ void cerver_stat_cache_store(cerver_stat_cache_t* cache, const char* path, size_t file_size,
275
+ time_t mtime);
205
276
 
206
277
  #endif /* CERVER_H */