/[osn-commons]/trunk/freehttpd/http_error.c
ViewVC logotype

Contents of /trunk/freehttpd/http_error.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 46 - (show annotations)
Mon Aug 12 16:55:32 2024 UTC (7 months, 2 weeks ago) by rakinar2
File MIME type: text/x-c
File size: 6803 byte(s)
feat(freehttpd): better error handling
1 #include "http_error.h"
2 #include "html/default_layout.h"
3 #include "log.h"
4 #include "response.h"
5
6 #include <stddef.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #define SERVER_SIGNATURE \
11 "FreeHTTPD/1.0.0 (Ubuntu 24.04 LTS) Server at localhost"
12
13 /* clang-format off */
14 static unsigned int valid_statuses[] = {
15 200, 201, 202, 204, 206,
16 300, 301, 302, 303, 304, 307, 308,
17 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413,
18 414, 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451,
19 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,
20 };
21 /* clang-format on */
22
23 static unsigned int valid_statuses_count
24 = sizeof (valid_statuses) / sizeof (valid_statuses[0]);
25
26 freehttpd_errdoc_tbl_t *
27 freehttpd_error_document_tbl_init (void)
28 {
29 freehttpd_errdoc_tbl_t *errdoc_tbl
30 = calloc (1, sizeof (freehttpd_errdoc_tbl_t));
31
32 if (errdoc_tbl == NULL)
33 return NULL;
34
35 errdoc_tbl->errdocs
36 = calloc (valid_statuses_count, sizeof (freehttpd_errdoc_t));
37
38 if (errdoc_tbl->errdocs == NULL)
39 return NULL;
40
41 errdoc_tbl->errdocs_cap = valid_statuses_count;
42 return errdoc_tbl;
43 }
44
45 void
46 freehttpd_error_document_tbl_free (freehttpd_errdoc_tbl_t *errdoc_tbl)
47 {
48 if (errdoc_tbl == NULL)
49 return;
50
51 if (errdoc_tbl->errdocs != NULL)
52 {
53 for (size_t i = 0; i < errdoc_tbl->errdocs_count; i++)
54 {
55 freehttpd_errdoc_t *errdoc = &errdoc_tbl->errdocs[i];
56
57 if (errdoc->auto_free == true && errdoc->document != NULL)
58 free ((void *) errdoc->document);
59 }
60
61 free (errdoc_tbl->errdocs);
62 }
63
64 free (errdoc_tbl);
65 }
66
67 static unsigned int
68 hash_function (freehttpd_status_t status)
69 {
70 return status % valid_statuses_count;
71 }
72
73 const freehttpd_errdoc_t *
74 freehttpd_error_document_get (freehttpd_errdoc_tbl_t *errdoc_tbl,
75 freehttpd_status_t status)
76 {
77 unsigned int hash = hash_function (status);
78
79 if (hash >= errdoc_tbl->errdocs_cap)
80 {
81 log_err (LOG_ERR "Invalid status code: %d: Hash overflow", status);
82 return NULL;
83 }
84
85 freehttpd_errdoc_t *errdoc = &errdoc_tbl->errdocs[hash];
86 bool second_round = false;
87 unsigned int index = hash;
88
89 while (errdoc_tbl->errdocs[index].status != status)
90 {
91 if (errdoc_tbl->errdocs[index].status == 0)
92 return NULL;
93
94 index++;
95
96 if (index >= errdoc_tbl->errdocs_cap)
97 {
98 second_round = true;
99 index = 0;
100 }
101
102 if (second_round && index >= hash)
103 return NULL;
104 }
105
106 return errdoc;
107 }
108
109 freehttpd_errdoc_t *
110 freehttpd_error_document_set (freehttpd_errdoc_tbl_t *errdoc_tbl,
111 freehttpd_status_t status, const char *document,
112 size_t document_length)
113 {
114 unsigned int hash = hash_function (status);
115 freehttpd_errdoc_t *errdoc = NULL;
116
117 if (hash >= errdoc_tbl->errdocs_cap)
118 {
119 log_err (LOG_ERR "Invalid status code: %d: Hash overflow: %u\n",
120 status, hash);
121 return NULL;
122 }
123
124 if (errdoc_tbl->errdocs_count >= errdoc_tbl->errdocs_cap)
125 {
126 log_err (LOG_ERR "Error documents table is full\n");
127 return NULL;
128 }
129
130 errdoc = &errdoc_tbl->errdocs[hash];
131
132 if (errdoc->document != NULL && errdoc->auto_free == true)
133 free ((void *) errdoc->document);
134
135 errdoc->status = status;
136 errdoc->document = document;
137 errdoc->document_length = document_length;
138 errdoc_tbl->errdocs_count++;
139 errdoc->auto_free = true;
140
141 return errdoc;
142 }
143
144 void
145 freehttpd_error_document_load_defaults (freehttpd_errdoc_tbl_t *errdoc_tbl)
146 {
147 const char *placeholders[] = {
148 "{FREEHTTPD_STATUS}",
149 "{FREEHTTPD_STATUS_TEXT}",
150 "{FREEHTTPD_SIGNATURE}",
151 "{FREEHTTPD_STATUS_DESCRIPTION}",
152 };
153
154 for (unsigned int i = 0;
155 i < sizeof (valid_statuses) / sizeof (valid_statuses[0]); i++)
156 {
157 freehttpd_errdoc_t *doc = freehttpd_error_document_set (
158 errdoc_tbl, valid_statuses[i],
159 (const char *) default_layout_html, default_layout_html_len);
160
161 char status_code[4];
162 const char *values[] = {
163 status_code,
164 freehttpd_response_status_text (valid_statuses[i]),
165 SERVER_SIGNATURE,
166 freehttpd_response_status_description (valid_statuses[i]),
167 };
168
169 snprintf (status_code, sizeof (status_code), "%d",
170 valid_statuses[i]);
171
172 doc->auto_free = false;
173
174 for (unsigned int j = 0;
175 j < sizeof (placeholders) / sizeof (placeholders[0]); j++)
176 {
177 char *placeholder
178 = strstr ((char *) doc->document, placeholders[j]);
179
180 while (placeholder != NULL)
181 {
182 size_t placeholder_len = strlen (placeholders[j]);
183 size_t value_len = strlen (values[j]);
184 size_t new_len = doc->document_length + value_len
185 - placeholder_len;
186 char buffer[new_len + 1];
187 bzero (buffer, sizeof (buffer));
188
189 memcpy (buffer, doc->document,
190 placeholder - doc->document);
191 memcpy (buffer + (placeholder - doc->document),
192 values[j], value_len);
193 memcpy (buffer + (placeholder - doc->document)
194 + value_len,
195 placeholder + placeholder_len,
196 doc->document_length
197 - (placeholder - doc->document)
198 - placeholder_len);
199
200 buffer[new_len] = 0;
201
202 if (doc->auto_free == true)
203 free ((void *) doc->document);
204 else
205 doc->auto_free = true;
206
207 doc->document_length = new_len;
208 doc->document = strdup (buffer);
209 placeholder = strstr ((char *) doc->document,
210 placeholders[j]);
211 }
212 }
213 }
214 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26