1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
/* 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 <dynstr.h>
#include <libweb/handler.h>
#include <libweb/html.h>
#include <libweb/http.h>
#include <errno.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 enum http_op op, const char *const res,
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;
}
|