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

Annotation of /trunk/freehttpd/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 46 - (hide annotations)
Mon Aug 12 16:55:32 2024 UTC (7 months, 3 weeks ago) by rakinar2
File MIME type: text/x-c
File size: 8140 byte(s)
feat(freehttpd): better error handling
1 rakinar2 46 #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