Line data Source code
1 : /*
2 : * lwan - web server
3 : * Copyright (c) 2012 L. A. F. Pereira <l@tia.mat.br>
4 : *
5 : * This program is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU General Public License
7 : * as published by the Free Software Foundation; either version 2
8 : * of the License, or any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : * GNU General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU General Public License
16 : * along with this program; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 : * USA.
19 : */
20 :
21 : #pragma once
22 :
23 : #if defined(__cplusplus)
24 : extern "C" {
25 : #endif
26 :
27 : #include <netinet/in.h>
28 : #include <pthread.h>
29 : #include <stdbool.h>
30 : #include <stdint.h>
31 : #include <string.h>
32 :
33 : #include "hash.h"
34 : #include "timeout.h"
35 : #include "lwan-array.h"
36 : #include "lwan-config.h"
37 : #include "lwan-coro.h"
38 : #include "lwan-status.h"
39 : #include "lwan-strbuf.h"
40 : #include "lwan-trie.h"
41 :
42 : #if defined(__cplusplus)
43 : #define ZERO_IF_IS_ARRAY(array) 0
44 : #else
45 : /* This macro expands to 0 if its parameter is an array, and causes a
46 : * compilation error otherwise. This is used by the N_ELEMENTS() macro to catch
47 : * invalid usages of this macro (e.g. when using arrays decayed to pointers) */
48 : #define ZERO_IF_IS_ARRAY(array) \
49 : (!sizeof(char[1 - 2 * __builtin_types_compatible_p( \
50 : __typeof__(array), __typeof__(&(array)[0]))]))
51 : #endif
52 :
53 : #define N_ELEMENTS(array) \
54 : (ZERO_IF_IS_ARRAY(array) | sizeof(array) / sizeof(array[0]))
55 :
56 :
57 : #ifdef __APPLE__
58 : #define LWAN_SECTION_NAME(name_) "__DATA," #name_
59 : #else
60 : #define LWAN_SECTION_NAME(name_) #name_
61 : #endif
62 :
63 : #define LWAN_MODULE_REF(name_) lwan_module_info_##name_.module
64 : #define LWAN_MODULE_FORWARD_DECL(name_) \
65 : extern const struct lwan_module_info lwan_module_info_##name_;
66 : #define LWAN_REGISTER_MODULE(name_, module_) \
67 : const struct lwan_module_info \
68 : __attribute__((used, section(LWAN_SECTION_NAME(lwan_module)))) \
69 : lwan_module_info_##name_ = {.name = #name_, .module = module_}
70 :
71 : #define LWAN_HANDLER_REF(name_) lwan_handler_##name_
72 :
73 : #define LWAN_HANDLER_ROUTE(name_, route_) \
74 : static enum lwan_http_status lwan_handler_##name_( \
75 : struct lwan_request *, struct lwan_response *, void *); \
76 : static const struct lwan_handler_info \
77 : __attribute__((used, section(LWAN_SECTION_NAME(lwan_handler)))) \
78 : __attribute__((aligned(8))) /* FIXME: why is this alignment needed? */ \
79 : lwan_handler_info_##name_ = { \
80 : .name = #name_, \
81 : .route = route_, \
82 : .handler = lwan_handler_##name_, \
83 : }; \
84 : __attribute__((used)) static enum lwan_http_status lwan_handler_##name_( \
85 : struct lwan_request *request __attribute__((unused)), \
86 : struct lwan_response *response __attribute__((unused)), \
87 : void *data __attribute__((unused)))
88 : #define LWAN_HANDLER(name_) LWAN_HANDLER_ROUTE(name_, NULL)
89 :
90 : #define ALWAYS_INLINE inline __attribute__((always_inline))
91 :
92 : #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
93 : #define STR4_INT(a, b, c, d) ((uint32_t)((a) | (b) << 8 | (c) << 16 | (d) << 24))
94 : #define STR2_INT(a, b) ((uint16_t)((a) | (b) << 8))
95 : #define STR8_INT(a, b, c, d, e, f, g, h) \
96 : ((uint64_t)STR4_INT(a, b, c, d) | (uint64_t)STR4_INT(e, f, g, h) << 32)
97 : #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
98 : #define STR4_INT(d, c, b, a) ((uint32_t)((a) | (b) << 8 | (c) << 16 | (d) << 24))
99 : #define STR2_INT(b, a) ((uint16_t)((a) | (b) << 8))
100 : #define STR8_INT(a, b, c, d, e, f, g, h) \
101 : ((uint64_t)STR4_INT(a, b, c, d) << 32 | (uint64_t)STR4_INT(e, f, g, h))
102 : #elif __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__
103 : #error A PDP? Seriously?
104 : #endif
105 :
106 : static ALWAYS_INLINE uint16_t string_as_uint16(const char *s)
107 : {
108 : uint16_t u;
109 :
110 2344 : memcpy(&u, s, sizeof(u));
111 :
112 2344 : return u;
113 : }
114 :
115 : static ALWAYS_INLINE uint32_t string_as_uint32(const char *s)
116 : {
117 : uint32_t u;
118 :
119 6498 : memcpy(&u, s, sizeof(u));
120 :
121 6498 : return u;
122 : }
123 :
124 : static ALWAYS_INLINE uint64_t string_as_uint64(const char *s)
125 : {
126 : uint64_t u;
127 :
128 593 : memcpy(&u, s, sizeof(u));
129 :
130 593 : return u;
131 : }
132 :
133 : #define LOWER2(s) ((s) | (uint16_t)0x2020)
134 : #define LOWER4(s) ((s) | (uint32_t)0x20202020)
135 : #define LOWER8(s) ((s) | (uint64_t)0x2020202020202020)
136 :
137 : #define STR2_INT_L(a, b) LOWER2(STR2_INT(a, b))
138 : #define STR4_INT_L(a, b, c, d) LOWER4(STR4_INT(a, b, c, d))
139 : #define STR8_INT_L(a, b, c, d, e, f, g, h) LOWER8(STR8_INT(a, b, c, d, e, f, g, h))
140 :
141 : #define STRING_SWITCH_SMALL(s) switch (string_as_uint16(s))
142 : #define STRING_SWITCH_SMALL_L(s) switch (LOWER2(string_as_uint16(s)))
143 : #define STRING_SWITCH(s) switch (string_as_uint32(s))
144 : #define STRING_SWITCH_L(s) switch (LOWER4(string_as_uint32(s)))
145 : #define STRING_SWITCH_LARGE(s) switch (string_as_uint64(s))
146 : #define STRING_SWITCH_LARGE_L(s) switch (LOWER8(string_as_uint64(s)))
147 :
148 : #define LIKELY_IS(x, y) __builtin_expect((x), (y))
149 : #define LIKELY(x) LIKELY_IS(!!(x), 1)
150 : #define UNLIKELY(x) LIKELY_IS((x), 0)
151 :
152 : #define ATOMIC_READ(V) (*(volatile typeof(V) *)&(V))
153 : #define ATOMIC_OP(P, O, V) (__sync_##O##_and_fetch((P), (V)))
154 : #define ATOMIC_AAF(P, V) ATOMIC_OP((P), add, (V))
155 : #define ATOMIC_SAF(P, V) ATOMIC_OP((P), sub, (V))
156 : #define ATOMIC_INC(V) ATOMIC_AAF(&(V), 1)
157 : #define ATOMIC_DEC(V) ATOMIC_SAF(&(V), 1)
158 :
159 : #if defined(__cplusplus)
160 : #define LWAN_ARRAY_PARAM(length) [length]
161 : #else
162 : #define LWAN_ARRAY_PARAM(length) [static length]
163 : #endif
164 :
165 : #define FOR_EACH_HTTP_STATUS(X) \
166 : X(SWITCHING_PROTOCOLS, 101, "Switching protocols", "Protocol is switching over from HTTP") \
167 : X(OK, 200, "OK", "Success") \
168 : X(PARTIAL_CONTENT, 206, "Partial content", "Delivering part of requested resource") \
169 : X(MOVED_PERMANENTLY, 301, "Moved permanently", "This content has moved to another place") \
170 : X(NOT_MODIFIED, 304, "Not modified", "The content has not changed since previous request") \
171 : X(TEMPORARY_REDIRECT, 307, "Temporary Redirect", "This content can be temporarily found at a different location") \
172 : X(BAD_REQUEST, 400, "Bad request", "The client has issued a bad request") \
173 : X(NOT_AUTHORIZED, 401, "Not authorized", "Client has no authorization to access this resource") \
174 : X(FORBIDDEN, 403, "Forbidden", "Access to this resource has been denied") \
175 : X(NOT_FOUND, 404, "Not found", "The requested resource could not be found on this server") \
176 : X(NOT_ALLOWED, 405, "Not allowed", "The requested method is not allowed by this server") \
177 : X(TIMEOUT, 408, "Request timeout", "Client did not produce a request within expected timeframe") \
178 : X(TOO_LARGE, 413, "Request too large", "The request entity is too large") \
179 : X(RANGE_UNSATISFIABLE, 416, "Requested range unsatisfiable", "The server can't supply the requested portion of the requested resource") \
180 : X(I_AM_A_TEAPOT, 418, "I'm a teapot", "Client requested to brew coffee but device is a teapot") \
181 : X(CLIENT_TOO_HIGH, 420, "Client too high", "Client is too high to make a request") \
182 : X(INTERNAL_ERROR, 500, "Internal server error", "The server encountered an internal error that couldn't be recovered from") \
183 : X(NOT_IMPLEMENTED, 501, "Not implemented", "Server lacks the ability to fulfil the request") \
184 : X(UNAVAILABLE, 503, "Service unavailable", "The server is either overloaded or down for maintenance") \
185 : X(SERVER_TOO_HIGH, 520, "Server too high", "The server is too high to answer the request")
186 :
187 : #define GENERATE_ENUM_ITEM(id, code, short, long) HTTP_ ## id = code,
188 : enum lwan_http_status {
189 : HTTP_CLASS__INFORMATIONAL = 100,
190 : HTTP_CLASS__SUCCESS = 200,
191 : HTTP_CLASS__REDIRECT = 300,
192 : HTTP_CLASS__CLIENT_ERROR = 400,
193 : HTTP_CLASS__SERVER_ERROR = 500,
194 :
195 : FOR_EACH_HTTP_STATUS(GENERATE_ENUM_ITEM)
196 : };
197 : #undef GENERATE_ENUM_ITEM
198 :
199 : enum lwan_handler_flags {
200 : HANDLER_EXPECTS_BODY_DATA = 1 << 0,
201 : HANDLER_MUST_AUTHORIZE = 1 << 1,
202 : HANDLER_CAN_REWRITE_URL = 1 << 2,
203 : HANDLER_DATA_IS_HASH_TABLE = 1 << 3,
204 :
205 : HANDLER_PARSE_MASK = HANDLER_EXPECTS_BODY_DATA,
206 : };
207 :
208 : /* 1<<0 set: response has body; see has_response_body() in lwan-response.c */
209 : /* 1<<3 set: request has body; see request_has_body() in lwan-request.c */
210 : #define FOR_EACH_REQUEST_METHOD(X) \
211 : X(GET, get, (1 << 0), (STR4_INT('G', 'E', 'T', ' ')), 0.6) \
212 : X(POST, post, (1 << 3 | 1 << 1 | 1 << 0), (STR4_INT('P', 'O', 'S', 'T')), 0.2)\
213 : X(HEAD, head, (1 << 1), (STR4_INT('H', 'E', 'A', 'D')), 0.2) \
214 : X(OPTIONS, options, (1 << 2), (STR4_INT('O', 'P', 'T', 'I')), 0.1) \
215 : X(DELETE, delete, (1 << 1 | 1 << 2), (STR4_INT('D', 'E', 'L', 'E')), 0.1) \
216 : X(PUT, put, (1 << 3 | 1 << 2 | 1 << 0), (STR4_INT('P', 'U', 'T', ' ')), 0.1)
217 :
218 : #define SELECT_MASK(upper, lower, mask, constant, probability) mask |
219 : #define GENERATE_ENUM_ITEM(upper, lower, mask, constant, probability) REQUEST_METHOD_##upper = mask,
220 :
221 : enum lwan_request_flags {
222 : REQUEST_ALL_FLAGS = -1,
223 :
224 : REQUEST_METHOD_MASK = FOR_EACH_REQUEST_METHOD(SELECT_MASK) 0,
225 : FOR_EACH_REQUEST_METHOD(GENERATE_ENUM_ITEM)
226 :
227 : REQUEST_ACCEPT_DEFLATE = 1 << 4,
228 : REQUEST_ACCEPT_GZIP = 1 << 5,
229 : REQUEST_ACCEPT_BROTLI = 1 << 6,
230 : REQUEST_ACCEPT_ZSTD = 1 << 7,
231 : REQUEST_ACCEPT_MASK = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7,
232 :
233 : REQUEST_IS_HTTP_1_0 = 1 << 8,
234 : REQUEST_ALLOW_PROXY_REQS = 1 << 9,
235 : REQUEST_PROXIED = 1 << 10,
236 : REQUEST_ALLOW_CORS = 1 << 11,
237 :
238 : RESPONSE_SENT_HEADERS = 1 << 12,
239 : RESPONSE_CHUNKED_ENCODING = 1 << 13,
240 : RESPONSE_NO_CONTENT_LENGTH = 1 << 14,
241 : RESPONSE_NO_EXPIRES = 1 << 15,
242 : RESPONSE_URL_REWRITTEN = 1 << 16,
243 :
244 : RESPONSE_STREAM = 1 << 17,
245 :
246 : REQUEST_PARSED_QUERY_STRING = 1 << 18,
247 : REQUEST_PARSED_IF_MODIFIED_SINCE = 1 << 19,
248 : REQUEST_PARSED_RANGE = 1 << 20,
249 : REQUEST_PARSED_FORM_DATA = 1 << 21,
250 : REQUEST_PARSED_COOKIES = 1 << 22,
251 : REQUEST_PARSED_ACCEPT_ENCODING = 1 << 23,
252 :
253 : RESPONSE_INCLUDE_REQUEST_ID = 1 << 24,
254 :
255 : REQUEST_HAS_QUERY_STRING = 1 << 25,
256 :
257 : REQUEST_WANTS_HSTS_HEADER = 1 << 26,
258 : };
259 :
260 : #undef SELECT_MASK
261 : #undef GENERATE_ENUM_ITEM
262 :
263 : enum lwan_connection_flags {
264 : CONN_MASK = -1,
265 :
266 : /* These flags have smaller numbers so that the table to convert
267 : * them to epoll events is smaller. See conn_flags_to_epoll_events(). */
268 : CONN_EVENTS_READ = 1 << 0,
269 : CONN_EVENTS_WRITE = 1 << 1,
270 : CONN_EVENTS_READ_WRITE = CONN_EVENTS_READ | CONN_EVENTS_WRITE,
271 : CONN_EVENTS_MASK = 1 << 0 | 1 << 1,
272 :
273 : CONN_IS_KEEP_ALIVE = 1 << 2,
274 :
275 : /* WebSockets-related flags. */
276 : CONN_IS_UPGRADE = 1 << 3,
277 : CONN_IS_WEBSOCKET = 1 << 4,
278 :
279 : /* These are used for a few different things:
280 : * - Avoid re-deferring callbacks to remove request from the timeout wheel
281 : * after it has slept previously and is requesting to sleep again. (The
282 : * timeout defer is disarmed right after resuming, and is only there because
283 : * connections may be closed when they're suspended.)
284 : * - Distinguish file descriptor in event loop between the connection and
285 : * an awaited file descriptor. (This is set in the connection that's awaiting
286 : * since the pointer to the connection is used as user_data in both cases.
287 : * This is required to be able to resume the connection coroutine after the
288 : * await is completed, and to bubble up errors in awaited file descriptors to
289 : * request handlers rather than abruptly closing the connection.) */
290 : CONN_SUSPENDED = 1 << 5,
291 : CONN_HAS_REMOVE_SLEEP_DEFER = 1 << 6,
292 : CONN_AWAITED_FD = CONN_SUSPENDED | CONN_HAS_REMOVE_SLEEP_DEFER,
293 :
294 : /* Used when HTTP pipelining has been detected. This enables usage of the
295 : * MSG_MORE flags when sending responses to batch as many short responses
296 : * as possible in a single TCP fragment. */
297 : CONN_CORK = 1 << 7,
298 :
299 : /* Set only on file descriptors being watched by async/await to determine
300 : * which epoll operation to use when suspending/resuming (ADD/MOD). Reset
301 : * whenever associated client connection is closed. */
302 : CONN_ASYNC_AWAIT = 1 << 8,
303 :
304 : CONN_SENT_CONNECTION_HEADER = 1 << 9,
305 :
306 : /* Both are used to know if an epoll event pertains to a listener rather
307 : * than a client. */
308 : CONN_LISTENER_HTTP = 1 << 10,
309 : CONN_LISTENER_HTTPS = 1 << 11,
310 :
311 : /* Is this a TLS connection? */
312 : CONN_TLS = 1 << 12,
313 : };
314 :
315 : enum lwan_connection_coro_yield {
316 : /* Returns to the event loop and terminates the coroutine, freeing
317 : * all resources associated with it, including calling deferred
318 : * callback, and the coroutine itself. */
319 : CONN_CORO_ABORT,
320 :
321 : /* Return to the event loop without changing the epoll event mask
322 : * or any other flag in this coroutine. */
323 : CONN_CORO_YIELD,
324 :
325 : /* Returns to the event loop, and optionally change the epoll event
326 : * mask (if it's not already the expected one.) */
327 : CONN_CORO_WANT_READ,
328 : CONN_CORO_WANT_WRITE,
329 : CONN_CORO_WANT_READ_WRITE,
330 :
331 : /* If a connection coroutine yields with CONN_CORO_SUSPEND, then
332 : * it'll be resumed using CONN_CORO_RESUME from the event loop.
333 : * CONN_CORO_RESUME should never be used from within connections
334 : * themselves, and should be considered a private API. */
335 : CONN_CORO_SUSPEND,
336 : CONN_CORO_RESUME,
337 :
338 : /* Group async stuff together to make it easier to check if a connection
339 : * coroutine is yielding because of async reasons. */
340 : CONN_CORO_ASYNC_AWAIT_READ,
341 : CONN_CORO_ASYNC_AWAIT_WRITE,
342 : CONN_CORO_ASYNC_AWAIT_READ_WRITE,
343 :
344 : CONN_CORO_MAX,
345 :
346 : /* Private API used by the async/await mechanism. Shouldn't be used
347 : * by handlers. */
348 : CONN_CORO_ASYNC = CONN_CORO_ASYNC_AWAIT_READ,
349 : };
350 :
351 : struct lwan_key_value {
352 : char *key;
353 : char *value;
354 : };
355 :
356 : struct lwan_request;
357 :
358 : struct lwan_response {
359 : struct lwan_strbuf *buffer;
360 : const char *mime_type;
361 :
362 : union {
363 : struct {
364 : const struct lwan_key_value *headers;
365 : };
366 :
367 : struct {
368 : enum lwan_http_status (*callback)(struct lwan_request *request,
369 : void *data);
370 : void *data;
371 : } stream;
372 : };
373 : };
374 :
375 : struct lwan_value {
376 : char *value;
377 : size_t len;
378 : };
379 :
380 : struct lwan_connection {
381 : /* This structure is exactly 32-bytes on x86-64. If it is changed,
382 : * make sure the scheduler (lwan-thread.c) is updated as well. */
383 : enum lwan_connection_flags flags;
384 : unsigned int time_to_expire;
385 : struct coro *coro;
386 : struct lwan_thread *thread;
387 : int prev, next; /* for timeout queue */
388 : };
389 :
390 : struct lwan_proxy {
391 : union {
392 : struct sockaddr_in ipv4;
393 : struct sockaddr_in6 ipv6;
394 : } from, to;
395 : };
396 :
397 1850 : DEFINE_ARRAY_TYPE(lwan_key_value_array, struct lwan_key_value)
398 :
399 : struct lwan_request_parser_helper;
400 :
401 : struct lwan_request {
402 : enum lwan_request_flags flags;
403 : int fd;
404 : struct lwan_connection *conn;
405 : const struct lwan_value *const global_response_headers;
406 :
407 : struct lwan_request_parser_helper *helper;
408 :
409 : struct lwan_value url;
410 : struct lwan_value original_url;
411 : struct lwan_response response;
412 :
413 : struct lwan_proxy *proxy;
414 : struct timeout timeout;
415 : };
416 :
417 : struct lwan_module {
418 : enum lwan_http_status (*handle_request)(struct lwan_request *request,
419 : struct lwan_response *response,
420 : void *instance);
421 :
422 : void *(*create)(const char *prefix, void *args);
423 : void *(*create_from_hash)(const char *prefix, const struct hash *hash);
424 : void (*destroy)(void *instance);
425 :
426 : bool (*parse_conf)(void *instance, struct config *config);
427 :
428 : enum lwan_handler_flags flags;
429 : };
430 :
431 : struct lwan_module_info {
432 : const char *name;
433 : const struct lwan_module *module;
434 : };
435 :
436 : struct lwan_url_map_route_info {
437 : const char *route;
438 : enum lwan_http_status (*handler)(struct lwan_request *request,
439 : struct lwan_response *response,
440 : void *data);
441 : };
442 :
443 : struct lwan_handler_info {
444 : const char *name;
445 : enum lwan_http_status (*handler)(struct lwan_request *request,
446 : struct lwan_response *response,
447 : void *data);
448 : const char *route;
449 : };
450 :
451 : struct lwan_url_map {
452 : enum lwan_http_status (*handler)(struct lwan_request *request,
453 : struct lwan_response *response,
454 : void *data);
455 : void *data;
456 :
457 : const char *prefix;
458 : size_t prefix_len;
459 : enum lwan_handler_flags flags;
460 :
461 : const struct lwan_module *module;
462 : void *args;
463 :
464 : struct {
465 : char *realm;
466 : char *password_file;
467 : } authorization;
468 : };
469 :
470 : struct lwan_thread {
471 : struct lwan *lwan;
472 : struct {
473 : char date[30];
474 : char expires[30];
475 : } date;
476 : int epoll_fd;
477 : struct timeouts *wheel;
478 : int listen_fd;
479 : int tls_listen_fd;
480 : unsigned int cpu;
481 : pthread_t self;
482 : };
483 :
484 : struct lwan_straitjacket {
485 : const char *user_name;
486 : const char *chroot_path;
487 : bool drop_capabilities;
488 : };
489 :
490 : struct lwan_config {
491 : /* Field will be overridden during initialization. */
492 : enum lwan_request_flags request_flags;
493 : struct lwan_key_value *global_headers;
494 :
495 : char *listener;
496 : char *tls_listener;
497 : char *error_template;
498 : char *config_file_path;
499 :
500 : struct {
501 : char *cert;
502 : char *key;
503 : bool send_hsts_header;
504 : } ssl;
505 :
506 : size_t max_post_data_size;
507 : size_t max_put_data_size;
508 :
509 : unsigned int keep_alive_timeout;
510 : unsigned int expires;
511 : unsigned int n_threads;
512 :
513 : bool quiet;
514 : bool proxy_protocol;
515 : bool allow_cors;
516 : bool allow_post_temp_file;
517 : bool allow_put_temp_file;
518 : };
519 :
520 : struct lwan {
521 : struct lwan_trie url_map_trie;
522 : struct lwan_connection *conns;
523 : struct lwan_value headers;
524 :
525 : #if defined(LWAN_HAVE_MBEDTLS)
526 : struct lwan_tls_context *tls;
527 : #endif
528 :
529 : struct {
530 : struct lwan_thread *threads;
531 :
532 : unsigned int max_fd;
533 : unsigned int count;
534 : pthread_barrier_t barrier;
535 : } thread;
536 :
537 : struct lwan_config config;
538 :
539 : unsigned int online_cpus;
540 : unsigned int available_cpus;
541 : };
542 :
543 : void lwan_set_url_map(struct lwan *l, const struct lwan_url_map *map);
544 : void lwan_detect_url_map(struct lwan *l);
545 : void lwan_main_loop(struct lwan *l);
546 :
547 : size_t lwan_prepare_response_header(struct lwan_request *request,
548 : enum lwan_http_status status,
549 : char header_buffer[],
550 : size_t header_buffer_size)
551 : __attribute__((warn_unused_result));
552 :
553 : const char *lwan_request_get_post_param(struct lwan_request *request,
554 : const char *key)
555 : __attribute__((warn_unused_result, pure));
556 : const char *lwan_request_get_query_param(struct lwan_request *request,
557 : const char *key)
558 : __attribute__((warn_unused_result, pure));
559 : const char *lwan_request_get_cookie(struct lwan_request *request,
560 : const char *key)
561 : __attribute__((warn_unused_result, pure));
562 : const char *lwan_request_get_header(struct lwan_request *request,
563 : const char *header)
564 : __attribute__((warn_unused_result));
565 :
566 : void lwan_request_sleep(struct lwan_request *request, uint64_t ms);
567 :
568 : bool lwan_response_set_chunked(struct lwan_request *request,
569 : enum lwan_http_status status);
570 : bool lwan_response_set_chunked_full(struct lwan_request *request,
571 : enum lwan_http_status status,
572 : const struct lwan_key_value *additional_headers);
573 : void lwan_response_send_chunk(struct lwan_request *request);
574 : void lwan_response_send_chunk_full(struct lwan_request *request,
575 : struct lwan_strbuf *strbuf);
576 :
577 : bool lwan_response_set_event_stream(struct lwan_request *request,
578 : enum lwan_http_status status);
579 : void lwan_response_send_event(struct lwan_request *request, const char *event);
580 :
581 : const char *lwan_determine_mime_type_for_file_name(const char *file_name)
582 : __attribute__((pure)) __attribute__((warn_unused_result));
583 :
584 : void lwan_init(struct lwan *l);
585 : void lwan_init_with_config(struct lwan *l, const struct lwan_config *config);
586 : void lwan_shutdown(struct lwan *l);
587 :
588 : static inline int lwan_main(void)
589 : {
590 : struct lwan l;
591 :
592 : lwan_init(&l);
593 :
594 : lwan_detect_url_map(&l);
595 : lwan_main_loop(&l);
596 :
597 : lwan_shutdown(&l);
598 :
599 : return 0;
600 : }
601 :
602 : const struct lwan_config *lwan_get_default_config(void);
603 :
604 : const char *lwan_request_get_host(struct lwan_request *request);
605 :
606 : const char *
607 : lwan_request_get_remote_address(struct lwan_request *request,
608 : char buffer LWAN_ARRAY_PARAM(INET6_ADDRSTRLEN))
609 : __attribute__((warn_unused_result));
610 :
611 : const char *
612 : lwan_request_get_remote_address_and_port(struct lwan_request *request,
613 : char buffer LWAN_ARRAY_PARAM(INET6_ADDRSTRLEN),
614 : uint16_t *port)
615 : __attribute__((warn_unused_result));
616 :
617 : static inline enum lwan_request_flags
618 1644 : lwan_request_get_method(const struct lwan_request *request)
619 : {
620 1644 : return (enum lwan_request_flags)(request->flags & REQUEST_METHOD_MASK);
621 : }
622 : const char *lwan_request_get_method_str(const struct lwan_request *request);
623 :
624 : int lwan_request_get_range(struct lwan_request *request,
625 : off_t *from,
626 : off_t *to);
627 : int lwan_request_get_if_modified_since(struct lwan_request *request,
628 : time_t *value);
629 : const struct lwan_value *
630 : lwan_request_get_request_body(struct lwan_request *request);
631 : const struct lwan_value *
632 : lwan_request_get_content_type(struct lwan_request *request);
633 : const struct lwan_key_value_array *
634 : lwan_request_get_cookies(struct lwan_request *request);
635 : const struct lwan_key_value_array *
636 : lwan_request_get_query_params(struct lwan_request *request);
637 : const struct lwan_key_value_array *
638 : lwan_request_get_post_params(struct lwan_request *request);
639 : enum lwan_request_flags
640 : lwan_request_get_accept_encoding(struct lwan_request *request);
641 :
642 : enum lwan_http_status
643 : lwan_request_websocket_upgrade(struct lwan_request *request);
644 : void lwan_response_websocket_write_text(struct lwan_request *request);
645 : void lwan_response_websocket_write_binary(struct lwan_request *request);
646 : int lwan_response_websocket_read(struct lwan_request *request);
647 : int lwan_response_websocket_read_hint(struct lwan_request *request, size_t size_hint);
648 :
649 : void lwan_request_await_read(struct lwan_request *r, int fd);
650 : void lwan_request_await_write(struct lwan_request *r, int fd);
651 : void lwan_request_await_read_write(struct lwan_request *r, int fd);
652 : ssize_t lwan_request_async_read(struct lwan_request *r, int fd, void *buf, size_t len);
653 : ssize_t lwan_request_async_read_flags(struct lwan_request *request, int fd, void *buf, size_t len, int flags);
654 : ssize_t lwan_request_async_write(struct lwan_request *r, int fd, const void *buf, size_t len);
655 : ssize_t lwan_request_async_writev(struct lwan_request *request,
656 : int fd,
657 : struct iovec *iov,
658 : int iov_count);
659 :
660 : void lwan_straitjacket_enforce(const struct lwan_straitjacket *sj);
661 :
662 : #if defined(__cplusplus)
663 : }
664 : #endif
|