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

Annotation of /trunk/freehttpd/http_error.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 46 - (hide 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 rakinar2 46 #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