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

Contents of /trunk/freehttpd/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 45 - (show annotations)
Sun Aug 11 17:35:46 2024 UTC (7 months, 2 weeks ago) by rakinar2
File MIME type: text/x-c
File size: 6753 byte(s)
feat(freehttpd): file serving and directory indexing

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26