quick commit 2
[webserver.git] / http.c
CommitLineData
d0b0d52b
ML
1#include <malloc.h>
2#include <string.h>
8a1d9e4a 3#include <time.h>
d0b0d52b
ML
4
5#include "debug.h"
4baf6839 6#include "file.h"
d0b0d52b
ML
7
8#include "http.h"
9
8a1d9e4a
LM
10#define BUFFER_SIZE 128
11
bb0468a5
LM
12#define HTTP_VERSION "HTTP/1.0"
13#define SERVER_NAME "Webserver/0.0.1"
14
8a1d9e4a 15char *codes[15] = {
bb0468a5
LM
16 "200 OK",
17 "201 Created",
18 "202 Accepted",
19 "204 No Content",
20 "301 Moved Permanently",
21 "302 Moved Temporarily",
22 "304 Not Modified",
23 "400 Bad Request",
24 "401 Unauthorized",
25 "403 Forbidden",
26 "404 Not Found",
27 "500 Internal Server Error",
28 "501 Not Implemented",
29 "502 Bad Gateway",
30 "503 Service Unavailable"};
31
32typedef enum {
33 c200 = 0, c201, c202, c204,
34 c301, c302, c304, c400,
35 c401, c403, c404, c500,
36 c501, c502, c503
37} code_t;
38
39typedef enum {
40 not_supported_e = 0, get_e, head_e, post_e
41} method_t;
42
43typedef struct {
44 char *allow;
45 char *authorization;
46 char *content_encoding;
47 char *content_length;
48 char *content_type;
49 char *date;
50 char *expires;
51 char *from;
52 char *if_modified_since;
53 char *last_modified;
54 char *location;
55 char *pragma;
56 char *referer;
57 char *server;
58 char *user_agent;
59 char *www_authenticate;
60} header_t;
61
62/* print header values */
63
64void print_header_values (header_t *header)
65{
66 printf ("allow = '%s'\n", header->allow);
67 printf ("authorization = '%s'\n", header->authorization);
68 printf ("content_encoding = '%s'\n", header->content_encoding);
69 printf ("content_length = '%s'\n", header->content_length);
70 printf ("content_type = '%s'\n", header->content_type);
71 printf ("date = '%s'\n", header->date);
72 printf ("expires = '%s'\n", header->expires);
73 printf ("from = '%s'\n", header->from);
74 printf ("if_modified_since = '%s'\n", header->if_modified_since);
75 printf ("last_modified = '%s'\n", header->last_modified);
76 printf ("location = '%s'\n", header->location);
77 printf ("pragma = '%s'\n", header->pragma);
78 printf ("referer = '%s'\n", header->referer);
79 printf ("server = '%s'\n", header->server);
80 printf ("user_agent = '%s'\n", header->user_agent);
81 printf ("www_authenticate = '%s'\n", header->www_authenticate);
82}
83
84/* find sequence*/
85
86char *find_sequence (char *data, int len, char *seq, char **pdata)
87{
88
89 int size = strlen (seq);
90
91 int i;
92 for (i = 0; i < len - size + 1; i++) {
93 if (strncmp (data + i, seq, size) == 0) {
94 data[i] = 0;
95 if (pdata != NULL) {
96 *pdata = data + i + size;
97 }
98 return data;
99 }
100 }
101
102 return NULL;
103}
104
105/* response entity */
106
8a1d9e4a 107int add_line (char **buffer, char *str)
bb0468a5 108{
8a1d9e4a
LM
109 int len = strlen (*buffer) + strlen (str) + 1;
110 *buffer = realloc (*buffer, len);
111 strcat (*buffer, str);
d0b0d52b
ML
112 return len;
113}
114
8a1d9e4a 115int add_status_line (char **buffer, code_t code)
bb0468a5 116{
8a1d9e4a
LM
117 char tmp[BUFFER_SIZE] = {0};
118
119 /* Status */
120 sprintf (tmp, "%s %s\r\n", HTTP_VERSION, codes[code]);
121 add_line (buffer, tmp);
122
123 return strlen (*buffer);
bb0468a5
LM
124}
125
8a1d9e4a 126int add_general_header (char **buffer)
bb0468a5 127{
8a1d9e4a
LM
128 char tmp[BUFFER_SIZE] = {0};
129
130 /* Date */
131 time_t ts = time (NULL);
132 sprintf (tmp, "Date: %s\r\n", ctime (&ts));
133 add_line (buffer, tmp);
134
135 /* Pragma */
136
137 return strlen (*buffer);
138}
139
140int add_response_header (char **buffer, char *uri)
141{
142 char tmp[BUFFER_SIZE] = {0};
143
144 /* Location */
145 sprintf (tmp, "Location: %s\r\n", uri);
146 add_line (buffer, tmp);
147
148 /* Server */
149 sprintf (tmp, "Server: %s\r\n", SERVER_NAME);
150 add_line (buffer, tmp);
151
152 /* WWW-Authentificate */
153
154 return strlen (*buffer);
bb0468a5
LM
155}
156
8a1d9e4a 157int add_entity (char **buffer, unsigned char *entity, int size, char *type, char *encoding)
bb0468a5 158{
8a1d9e4a
LM
159 char tmp[BUFFER_SIZE] = {0};
160 int len = strlen (*buffer);
161
162 /* Allow */
163 /* Expires */
164 /* Last-Modified */
165
166 if (entity != NULL) {
167
168 /* Content-Encoding */
169 if (encoding != NULL) {
170 sprintf (tmp, "Content-Encoding: %s\r\n", encoding);
171 add_line (buffer, tmp);
172 }
173
174 /* Content-Length */
175 sprintf (tmp, "Content-Length: %d\r\n", size);
176 add_line (buffer, tmp);
177
178 /* Content-Type */
179 sprintf (tmp, "Content-Type: %s\r\n", type);
180 add_line (buffer, tmp);
181
182 add_line (buffer, "\r\n");
183
184 /* Entity */
185 len = strlen (*buffer);
186 *buffer = realloc (*buffer, len + size);
187 memcpy (*buffer + len, entity, size);
188 len += size;
189 }
190
bb0468a5
LM
191 return len;
192}
193
194/* error 400 */
195
196int error_400 (char **buffer)
197{
8a1d9e4a
LM
198 add_status_line (buffer, c400);
199 add_general_header (buffer);
200 add_response_header (buffer, NULL);
201
202 char *response = "<html><head><title>Error 400</title></head><body><p>Bad Request</p></body></html>";
203 return add_entity (buffer, (unsigned char *)response, strlen (response), "text/html", "iso-8859-1");
204}
205
4baf6839
LM
206/* error 404 */
207
208int error_404 (char **buffer, char *uri)
209{
210 add_status_line (buffer, c404);
211 add_general_header (buffer);
212 add_response_header (buffer, uri);
213
214 char *response = "<html><head><title>Error 404</title></head><body><p>File not found</p></body></html>";
215 return add_entity (buffer, (unsigned char *)response, strlen (response), "text/html", "iso-8859-1");
216}
217
8a1d9e4a
LM
218/* response html */
219
220int response_html (char **buffer, char *location, char *response)
221{
222 add_status_line (buffer, c200);
223 add_general_header (buffer);
224 add_response_header (buffer, location);
225
226 return add_entity (buffer, (unsigned char *)response, strlen (response), "text/html", "iso-8859-1");
bb0468a5
LM
227}
228
229/* trim string */
230
231char *trim (char *str)
232{
233 if (str != NULL) {
234 while ((*str == ' ') || (*str == '\t')) {
235 str++;
236 }
237 }
238 return str;
239}
240
241/* main HTTP processing */
242
4baf6839 243int processing (char *data, int len, char *root, char **pdata)
bb0468a5 244{
bb0468a5
LM
245 VERBOSE (DEBUG, PRINT ("Start processing\n"));
246
247 /* check method */
248 char *line = find_sequence (data, len, "\r\n", &data);
249 if (line == NULL) {
250 VERBOSE (WARNING, PRINT ("Unknown received data\n"));
251 if (pdata != NULL) {
252 *pdata = NULL;
253 }
254 return 0;
255 }
256 VERBOSE (DEBUG, PRINT ("Command line: '%s'\n", line));
257
258 char *method = strtok (line, " ");
259 char *uri = strtok (NULL, " ");
260 char *version = strtok (NULL, " ");
261 method_t type = not_supported_e;
262 if (strcmp (method, "GET") == 0) {
263 type = get_e;
264 } else if (strcmp ("HEAD", method) == 0) {
265 type = head_e;
266 } else if (strcmp ("POST", method) == 0) {
267 type = post_e;
268 } else {
269 VERBOSE (WARNING, PRINT ("Unkown method: %s\n", method));
bb0468a5
LM
270 return error_400 (pdata);
271 }
272 VERBOSE (INFO, PRINT ("%s %s (%s)\n", (type == get_e) ? "Get" : (type == head_e) ? "Head" : "Post", uri, version));
273
4baf6839 274 /* analyse uri */
6add28e9 275 char *filename = (char *)calloc (strlen (root) + strlen (uri) + 2, 1);
4baf6839
LM
276 //sprintf (filename, "%s%s%s", root, ((root[strlen (root) - 1] != '/') && (uri[0] != '/')) ? "/" : "", uri);
277 sprintf (filename, "%s/%s", root, uri);
278
bb0468a5
LM
279 /* check header */
280 header_t header = {0};
281 while (strcmp (line = find_sequence (data, len, "\r\n", &data), "") != 0) {
282 VERBOSE (DEBUG, PRINT ("Header line: '%s'\n", line));
283 char *field = strtok (line, ":");
284 char *value = trim (strtok (NULL, "\r"));
285 VERBOSE (DEBUG, PRINT ("Field: %s\nValue: %s\n", field, value));
286 if (*line == 0) {
287 break;
288 }
289
290 VERBOSE (DEBUG, PRINT ("Analyse field\n"));
291 if (strcmp (field, "Allow") == 0) {
292 header.allow = value;
293 } else if (strcmp (field, "Authorization") == 0) {
294 header.authorization = value;
295 } else if (strcmp (field, "Content-Encoding") == 0) {
296 header.content_encoding = value;
297 } else if (strcmp (field, "Content-Length") == 0) {
298 header.content_length = value;
299 } else if (strcmp (field, "Content-Type") == 0) {
300 header.content_type = value;
301 } else if (strcmp (field, "Date") == 0) {
302 header.date = value;
303 } else if (strcmp (field, "Expires") == 0) {
304 header.expires = value;
305 } else if (strcmp (field, "From") == 0) {
306 header.from = value;
307 } else if (strcmp (field, "If-Modified-Since") == 0) {
308 header.if_modified_since = value;
309 } else if (strcmp (field, "Last-Modified") == 0) {
310 header.last_modified = value;
311 } else if (strcmp (field, "Location") == 0) {
312 header.location = value;
313 } else if (strcmp (field, "Pragma") == 0) {
314 header.pragma = value;
315 } else if (strcmp (field, "Referer") == 0) {
316 header.referer = value;
317 } else if (strcmp (field, "Server") == 0) {
318 header.server = value;
319 } else if (strcmp (field, "User-Agent") == 0) {
320 header.user_agent = value;
321 } else if (strcmp (field, "WWW-Authenticate") == 0) {
322 header.www_authenticate = value;
323 } else {
324 VERBOSE (WARNING, PRINT ("Unknown header field: '%s'\n", field));
325 }
326 }
327 VERBOSE (DEBUG, print_header_values (&header));
328
bb0468a5 329 /* response */
4baf6839 330 char *buffer = NULL;
8a1d9e4a
LM
331 switch (type) {
332 case get_e:
6add28e9 333 VERBOSE (DEBUG, PRINT ("Read file %s\n", filename));
4baf6839
LM
334 len = readfile ((unsigned char **)&buffer, filename);
335 if (len == 0) {
336 len = error_404 (pdata, "http://localhost/");
337 } else {
338 len = response_html (pdata, "http://localhost/", buffer);
339 free (buffer);
340 }
8a1d9e4a
LM
341 break;
342 case head_e:
343 break;
344 case post_e:
6add28e9 345 VERBOSE (DEBUG, PRINT ("Write file %s\n", filename));
8a1d9e4a
LM
346 break;
347 case not_supported_e:
348 break;
349 }
350
4baf6839 351 /* cleaning */
6add28e9
LM
352 VERBOSE (DEBUG, PRINT ("Cleaning\n"));
353 if (filename) {
354 VERBOSE (DEBUG, PRINT ("Cleaning filename\n"));
355 free (filename);
356 }
4baf6839 357
8a1d9e4a 358 return len;
bb0468a5
LM
359}
360
d0b0d52b 361/* vim: set ts=4 sw=4 et: */