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

Contents of /trunk/freehttpd/response.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: 8140 byte(s)
feat(freehttpd): better error handling
1 #include "response.h"
2 #include <errno.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/socket.h>
8 #include <time.h>
9 #include <unistd.h>
10
11 freehttpd_response_t *
12 freehttpd_response_init (FILE *stream, const char *version, size_t version_len,
13 freehttpd_status_t status)
14 {
15 freehttpd_response_t *response = calloc (1, sizeof (freehttpd_response_t));
16
17 if (response == NULL)
18 return NULL;
19
20 response->stream = stream;
21 response->version = version == NULL ? NULL : strdup (version);
22 response->version_length = version == NULL ? 0
23 : version_len == 0 ? strlen (version)
24 : version_len;
25 response->status.code = status;
26 response->status.text
27 = status != 0 ? freehttpd_response_status_text (status) : NULL;
28 response->status.status_text_length = 0;
29 response->headers = NULL;
30 response->headers_length = 0;
31 response->buffer = NULL;
32 response->buffer_length = 0;
33
34 return response;
35 }
36
37 const char *
38 freehttpd_response_status_text (freehttpd_status_t status)
39 {
40 switch (status)
41 {
42 case FREEHTTPD_STATUS_OK:
43 return "OK";
44 case FREEHTTPD_STATUS_BAD_REQUEST:
45 return "Bad Request";
46 case FREEHTTPD_STATUS_NOT_FOUND:
47 return "Not Found";
48 case FREEHTTPD_STATUS_METHOD_NOT_ALLOWED:
49 return "Method Not Allowed";
50 case FREEHTTPD_STATUS_INTERNAL_SERVER_ERROR:
51 return "Internal Server Error";
52 case FREEHTTPD_STATUS_NOT_IMPLEMENTED:
53 return "Not Implemented";
54 case FREEHTTPD_STATUS_FORBIDDEN:
55 return "Forbidden";
56 default:
57 return "Unknown Status";
58 }
59 }
60
61 const char *
62 freehttpd_response_status_description (freehttpd_status_t status)
63 {
64 switch (status)
65 {
66 case FREEHTTPD_STATUS_BAD_REQUEST:
67 return "Your browser sent a request that this server could not "
68 "understand.";
69 case FREEHTTPD_STATUS_NOT_FOUND:
70 return "The requested URL was not found on this server.";
71 case FREEHTTPD_STATUS_METHOD_NOT_ALLOWED:
72 return "The requested method is not allowed for the URL.";
73 case FREEHTTPD_STATUS_NOT_IMPLEMENTED:
74 return "The server does not support the action requested by the "
75 "browser.";
76 case FREEHTTPD_STATUS_FORBIDDEN:
77 return "You don't have permission to access the requested URL on "
78 "this server.";
79 default:
80 return "The server encountered an internal error or "
81 "misconfiguration and was unable to complete your request.";
82 }
83 }
84
85 void
86 freehttpd_response_set_status (freehttpd_response_t *response,
87 freehttpd_status_t status)
88 {
89 response->status.code = status;
90 response->status.text = freehttpd_response_status_text (status);
91 }
92
93 void
94 freehttpd_response_add_default_headers (freehttpd_response_t *response)
95 {
96 response->headers
97 = realloc (response->headers, sizeof (freehttpd_header_t)
98 * (response->headers_length + 3));
99 response->headers[response->headers_length++]
100 = freehttpd_header_init_stack ("Server", "freehttpd", 6, 9);
101 response->headers[response->headers_length++]
102 = freehttpd_header_init_stack ("Connection", "close", 10, 5);
103
104 struct tm *time_info;
105 time_t raw_time;
106 time (&raw_time);
107 time_info = gmtime (&raw_time);
108
109 char time_str[64];
110 size_t time_strlen = strftime (time_str, sizeof (time_str),
111 "%a, %d %b %Y %H:%M:%S GMT", time_info);
112
113 response->headers[response->headers_length++]
114 = freehttpd_header_init_stack ("Date", time_str, 4, time_strlen);
115 }
116
117 freehttpd_header_t *
118 freehttpd_response_add_header (freehttpd_response_t *response, const char *name,
119 size_t name_len, const char *value_fmt, ...)
120 {
121 va_list args;
122 char *final_value = NULL;
123 freehttpd_header_t *header;
124
125 va_start (args, value_fmt);
126 (void) (vasprintf (&final_value, value_fmt, args) + 1);
127 va_end (args);
128
129 response->headers
130 = realloc (response->headers, sizeof (freehttpd_header_t)
131 * (response->headers_length + 1));
132 response->headers[response->headers_length++]
133 = freehttpd_header_init_stack (name, NULL, name_len, 0);
134
135 header = &response->headers[response->headers_length - 1];
136 header->value = final_value;
137 header->value_length = strlen (final_value);
138
139 return response->headers + (response->headers_length - 1);
140 }
141
142 ecode_t
143 freehttpd_response_head_send (const freehttpd_response_t *response)
144 {
145 int ret = 0;
146
147 ret = fprintf (response->stream, "HTTP/%s %d %s\r\n", response->version,
148 response->status.code, response->status.text);
149
150 if (ret < 0)
151 return E_SYSCALL_WRITE;
152
153 for (size_t i = 0; i < response->headers_length; i++)
154 {
155 ret = fprintf (response->stream, "%s: %s\r\n",
156 response->headers[i].name,
157 response->headers[i].value);
158
159 if (ret < 0)
160 return E_SYSCALL_WRITE;
161 }
162
163 fflush (response->stream);
164 return E_OK;
165 }
166
167 ecode_t
168 freehttpd_response_begin_body (freehttpd_response_t *response)
169 {
170 if (fwrite ("\r\n", 1, 2, response->stream) != 2)
171 return E_SYSCALL_WRITE;
172
173 fflush (response->stream);
174 return E_OK;
175 }
176
177 ecode_t
178 freehttpd_response_begin_end (freehttpd_response_t *response)
179 {
180 return freehttpd_response_begin_body (response);
181 }
182
183 size_t
184 freehttpd_response_write (freehttpd_response_t *response, const void *data,
185 size_t size, size_t n)
186 {
187 size_t wsize = fwrite (data, size, n, response->stream);
188
189 if (wsize > 0)
190 {
191 int old_errno = errno;
192 fflush (response->stream);
193 errno = old_errno;
194 }
195
196 return wsize;
197 }
198
199 ecode_t
200 freehttpd_response_printf (freehttpd_response_t *response, const char *format,
201 ...)
202 {
203 va_list args;
204 va_start (args, format);
205 int ret = vfprintf (response->stream, format, args);
206 va_end (args);
207
208 if (ret < 0)
209 return E_SYSCALL_WRITE;
210
211 return E_OK;
212 }
213
214 ecode_t
215 freehttpd_response_bprintf (freehttpd_response_t *response, const char *format,
216 ...)
217 {
218 va_list args;
219 va_start (args, format);
220 char *str = NULL;
221 int ret = vasprintf (&str, format, args);
222 va_end (args);
223
224 if (ret < 0)
225 return E_SYSCALL_WRITE;
226
227 size_t new_len = strlen (str) + 1;
228 response->buffer_length += new_len;
229 response->buffer = realloc (response->buffer, response->buffer_length);
230 memcpy (response->buffer + response->buffer_length - new_len, str, new_len);
231 free (str);
232
233 return E_OK;
234 }
235
236 ecode_t
237 freehttpd_response_flush (freehttpd_response_t *response)
238 {
239 if (response->buffer == NULL)
240 return E_OK;
241
242 size_t written = 0;
243
244 while (written < response->buffer_length)
245 {
246 ssize_t ret
247 = fwrite (response->buffer + written, 1,
248 response->buffer_length - written, response->stream);
249
250 if (ret < 0)
251 return E_SYSCALL_WRITE;
252
253 written += ret;
254 }
255
256 fflush (response->stream);
257 free (response->buffer);
258 response->buffer = NULL;
259 response->buffer_length = 0;
260
261 return E_OK;
262 }
263
264 void
265 freehttpd_response_free (freehttpd_response_t *response)
266 {
267 if (response == NULL)
268 return;
269
270 if (response->version != NULL)
271 free (response->version);
272
273 if (response->headers != NULL)
274 {
275 for (size_t i = 0; i < response->headers_length; i++)
276 {
277 free (response->headers[i].name);
278 free (response->headers[i].value);
279 }
280 }
281
282 free (response->buffer);
283 free (response);
284 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26