/* As of FreeBSD 13.2, sigaction(2) still conforms to IEEE Std * 1003.1-1990 (POSIX.1), which did not define SA_RESTART. * FreeBSD supports it as an extension, but then _POSIX_C_SOURCE must * not be defined. */ #ifndef __FreeBSD__ #define _POSIX_C_SOURCE 200809L #endif #include #include #include #include #include #include #include #include #include #include static const size_t max_headers = 5; static int hello(const struct http_payload *const pl, struct http_response *const r, void *const user) { printf("Got %zu headers from the client (max %zu).\n", pl->n_headers, max_headers); for (size_t i = 0; i < pl->n_headers; i++) { const struct http_header *const h = &pl->headers[i]; printf("%s: %s\n", h->header, h->value); } *r = (const struct http_response) { .status = HTTP_STATUS_OK }; return 0; } static int on_length(const unsigned long long len, const struct http_cookie *const c, struct http_response *const r, void *const user) { *r = (const struct http_response) { .status = HTTP_STATUS_FORBIDDEN }; return 1; } struct handler *handler; static void handle_signal(const int signum) { switch (signum) { case SIGINT: /* Fall through. */ case SIGTERM: handler_notify_close(handler); break; default: break; } } static int init_signals(void) { struct sigaction sa = { .sa_handler = handle_signal, .sa_flags = SA_RESTART }; sigemptyset(&sa.sa_mask); static const struct signal { int signal; const char *name; } signals[] = { {.signal = SIGINT, .name = "SIGINT"}, {.signal = SIGTERM, .name = "SIGTERM"}, {.signal = SIGPIPE, .name = "SIGPIPE"} }; for (size_t i = 0; i < sizeof signals / sizeof *signals; i++) { const struct signal *const s = &signals[i]; if (sigaction(s->signal, &sa, NULL)) { fprintf(stderr, "%s: sigaction(2) %s: %s\n", __func__, s->name, strerror(errno)); return -1; } } return 0; } int main(int argc, char *argv[]) { int ret = EXIT_FAILURE; const struct handler_cfg cfg = { .length = on_length, .max_headers = max_headers }; static const char *const urls[] = {"/", "/index.html"}; if (!(handler = handler_alloc(&cfg))) { fprintf(stderr, "%s: handler_alloc failed\n", __func__); goto end; } for (size_t i = 0; i < sizeof urls / sizeof *urls; i++) if (handler_add(handler, urls[i], HTTP_OP_GET, hello, NULL)) { fprintf(stderr, "%s: handler_add failed\n", __func__); goto end; } unsigned short port; if (handler_listen(handler, 0, &port)) { fprintf(stderr, "%s: handler_listen failed\n", __func__); goto end; } printf("Listening on port %hu\n", port); if (handler_loop(handler)) { fprintf(stderr, "%s: handler_loop failed\n", __func__); goto end; } ret = EXIT_SUCCESS; end: handler_free(handler); return ret; }