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

Contents of /trunk/freehttpd/request.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: 7126 byte(s)
feat(freehttpd): better error handling
1 #include "request.h"
2 #include "freehttpd.h"
3 #include <ctype.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/socket.h>
8 #include <unistd.h>
9
10 freehttpd_request_t *
11 freehttpd_request_init (const char *method, const char *uri,
12 const char *version)
13 {
14 freehttpd_request_t *request = calloc (1, sizeof (freehttpd_request_t));
15
16 if (request == NULL)
17 return NULL;
18
19 if (method != NULL)
20 {
21 request->method = strdup (method);
22 request->method_length = strlen (method);
23 }
24
25 if (uri != NULL)
26 {
27 request->uri = strdup (uri);
28 request->uri_length = strlen (uri);
29 }
30
31 if (version != NULL)
32 {
33
34 request->version = strdup (version);
35 request->version_length = strlen (version);
36 }
37
38 return request;
39 }
40
41 freehttpd_header_t *
42 freehttpd_header_init (const char *name, const char *value, size_t name_length,
43 size_t value_length)
44 {
45 freehttpd_header_t *header = calloc (1, sizeof (freehttpd_header_t));
46
47 if (header == NULL)
48 return NULL;
49
50 freehttpd_header_t on_stack
51 = freehttpd_header_init_stack (name, value, name_length, value_length);
52 memcpy (header, &on_stack, sizeof (freehttpd_header_t));
53
54 return header;
55 }
56
57 freehttpd_header_t
58 freehttpd_header_init_stack (const char *name, const char *value,
59 size_t name_length, size_t value_length)
60 {
61 freehttpd_header_t header = { 0 };
62
63 if (name != NULL)
64 {
65 header.name = strdup (name);
66 header.name_length = name_length == 0 ? strlen (name) : name_length;
67 }
68
69 if (value != NULL)
70 {
71 header.value = strdup (value);
72 header.value_length
73 = value_length == 0 ? strlen (value) : value_length;
74 }
75
76 return header;
77 }
78
79 void
80 freehttpd_header_free (freehttpd_header_t *header)
81 {
82 if (header == NULL)
83 return;
84
85 if (header->name != NULL)
86 free (header->name);
87
88 if (header->value != NULL)
89 free (header->value);
90
91 free (header);
92 }
93
94 void
95 freehttpd_request_free (freehttpd_request_t *request)
96 {
97 if (request == NULL)
98 return;
99
100 if (request->method != NULL)
101 free (request->method);
102
103 if (request->uri != NULL)
104 free (request->uri);
105
106 if (request->version != NULL)
107 free (request->version - 5);
108
109 if (request->path != NULL)
110 free (request->path);
111
112 if (request->query != NULL)
113 free (request->query);
114
115 if (request->headers != NULL)
116 {
117 for (size_t i = 0; i < request->headers_count; i++)
118 freehttpd_header_free (request->headers[i]);
119
120 free (request->headers);
121 }
122
123 if (request->body != NULL)
124 free (request->body);
125
126 free (request);
127 }
128
129 static char *
130 urldecode (const char *input, size_t *len)
131 {
132 char *output = calloc (strlen (input) + 1, 1);
133
134 if (output == NULL)
135 return NULL;
136
137 size_t i = 0, j = 0;
138
139 for (; input[i] != 0; i++, j++)
140 {
141 if (input[i] == '%')
142 {
143 if (input[i + 1] == 0 || input[i + 2] == 0)
144 {
145 free (output);
146 return NULL;
147 }
148
149 char c1 = tolower (input[i + 1]);
150 char c2 = tolower (input[i + 2]);
151 int c1n = isdigit (c1) ? c1 - '0' : c1 - 'a' + 10;
152 int c2n = isdigit (c2) ? c2 - '0' : c2 - 'a' + 10;
153 int code = c1n * 16 + c2n;
154 output[j] = (char) code;
155 i += 2;
156 }
157 else
158 output[j] = input[i];
159 }
160
161 output[j] = 0;
162
163 printf ("output: %s\n", output);
164
165 if (len != NULL)
166 *len = j;
167
168 return output;
169 }
170
171 const char *const SUPPORTED_METHODS[]
172 = { "GET", "POST", "PUT", "DELETE", "HEAD",
173 "OPTIONS", "TRACE", "CONNECT", NULL };
174
175 freehttpd_request_t *
176 freehttpd_request_parse (freehttpd_t *freehttpd, int sockfd, ecode_t *error)
177 {
178 freehttpd_request_t *request = freehttpd_request_init (NULL, NULL, NULL);
179
180 if (request == NULL)
181 {
182 *error = E_LIBC_MALLOC;
183 return NULL;
184 }
185
186 const freehttpd_config_t *config = freehttpd_get_config (freehttpd);
187 char *buf[3] = { 0 };
188 char **buf_ptrs[] = { &request->method, &request->uri, &request->version };
189 size_t max_lengths[] = { config->max_method_len, config->max_uri_len,
190 config->max_version_len };
191 size_t *length_ptrs[] = { &request->method_length, &request->uri_length,
192 &request->version_length };
193
194 for (int i = 0; i < 3; i++)
195 {
196 char c;
197 size_t j = 0;
198
199 /* TODO: instead of always calling read with size 1, we could
200 optimize this by reading more bytes at once and then parsing
201 the buffer. */
202 while (recv (sockfd, &c, 1, 0) == 1)
203 {
204 if (isspace (c))
205 break;
206
207 if (j >= max_lengths[i])
208 {
209 freehttpd_request_free (request);
210 *error = E_MALFORMED_REQUEST;
211 return NULL;
212 }
213
214 buf[i] = realloc (buf[i], j + 1);
215 buf[i][j++] = c;
216 }
217
218 if (j == 0)
219 {
220 freehttpd_request_free (request);
221 *error = E_MALFORMED_REQUEST;
222 return NULL;
223 }
224
225 buf[i] = realloc (buf[i], j + 1);
226 buf[i][j] = 0;
227 *length_ptrs[i] = j;
228 *buf_ptrs[i] = buf[i];
229 }
230
231 for (size_t i = 0; SUPPORTED_METHODS[i] != NULL; i++)
232 {
233 if (strcmp (buf[0], SUPPORTED_METHODS[i]) == 0)
234 {
235 request->method = buf[0];
236 break;
237 }
238 }
239
240 if (request->method == NULL || request->uri == NULL
241 || request->version == NULL)
242 {
243 freehttpd_request_free (request);
244 *error = E_MALFORMED_REQUEST;
245 return NULL;
246 }
247
248 if (memcmp (request->version, "HTTP/", 5) != 0)
249 {
250 freehttpd_request_free (request);
251 *error = E_MALFORMED_REQUEST;
252 return NULL;
253 }
254
255 request->version += 5;
256 request->version_length -= 5;
257
258 char *path = strchr (request->uri, '?');
259
260 if (path != NULL)
261 {
262 path = strndup (request->uri, path - request->uri);
263 request->query = strdup (path + 1);
264 request->query_length
265 = request->uri_length - request->path_length - 1;
266 }
267 else
268 path = strdup (request->uri);
269
270 request->path = urldecode (path, &request->path_length);
271 free (path);
272 *error = E_OK;
273 return request;
274 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26