first http server working
[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{
cae06547
LM
66 printf ("Header values\n");
67 if (header->allow) printf ("allow = '%s'\n", header->allow);
68 if (header->authorization) printf ("authorization = '%s'\n", header->authorization);
69 if (header->content_encoding) printf ("content_encoding = '%s'\n", header->content_encoding);
70 if (header->content_length) printf ("content_length = '%s'\n", header->content_length);
71 if (header->content_type) printf ("content_type = '%s'\n", header->content_type);
72 if (header->date) printf ("date = '%s'\n", header->date);
73 if (header->expires) printf ("expires = '%s'\n", header->expires);
74 if (header->from) printf ("from = '%s'\n", header->from);
75 if (header->if_modified_since) printf ("if_modified_since = '%s'\n", header->if_modified_since);
76 if (header->last_modified) printf ("last_modified = '%s'\n", header->last_modified);
77 if (header->location) printf ("location = '%s'\n", header->location);
78 if (header->pragma) printf ("pragma = '%s'\n", header->pragma);
79 if (header->referer) printf ("referer = '%s'\n", header->referer);
80 if (header->server) printf ("server = '%s'\n", header->server);
81 if (header->user_agent) printf ("user_agent = '%s'\n", header->user_agent);
82 if (header->www_authenticate) printf ("www_authenticate = '%s'\n", header->www_authenticate);
bb0468a5
LM
83}
84
85/* find sequence*/
86
87char *find_sequence (char *data, int len, char *seq, char **pdata)
88{
89
90 int size = strlen (seq);
91
92 int i;
93 for (i = 0; i < len - size + 1; i++) {
94 if (strncmp (data + i, seq, size) == 0) {
95 data[i] = 0;
96 if (pdata != NULL) {
97 *pdata = data + i + size;
98 }
99 return data;
100 }
101 }
102
103 return NULL;
104}
105
106/* response entity */
107
8a1d9e4a 108int add_line (char **buffer, char *str)
bb0468a5 109{
50c7ef81
LM
110 VERBOSE (DEBUG, PRINT ("add line: %s", str));
111 int len = ((*buffer) ? strlen (*buffer) : 0) + strlen (str) + 1;
112 VERBOSE (DEBUG, PRINT ("len: %d\n", len));
113 if (*buffer) {
114 *buffer = (char *)realloc (*buffer, len);
115 } else {
116 *buffer = (char *)calloc (len, 1);
117 }
8a1d9e4a 118 strcat (*buffer, str);
d0b0d52b
ML
119 return len;
120}
121
8a1d9e4a 122int add_status_line (char **buffer, code_t code)
bb0468a5 123{
8a1d9e4a
LM
124 char tmp[BUFFER_SIZE] = {0};
125
126 /* Status */
127 sprintf (tmp, "%s %s\r\n", HTTP_VERSION, codes[code]);
128 add_line (buffer, tmp);
129
130 return strlen (*buffer);
bb0468a5
LM
131}
132
8a1d9e4a 133int add_general_header (char **buffer)
bb0468a5 134{
8a1d9e4a
LM
135 char tmp[BUFFER_SIZE] = {0};
136
137 /* Date */
138 time_t ts = time (NULL);
139 sprintf (tmp, "Date: %s\r\n", ctime (&ts));
140 add_line (buffer, tmp);
141
142 /* Pragma */
143
144 return strlen (*buffer);
145}
146
147int add_response_header (char **buffer, char *uri)
148{
149 char tmp[BUFFER_SIZE] = {0};
150
151 /* Location */
152 sprintf (tmp, "Location: %s\r\n", uri);
153 add_line (buffer, tmp);
154
155 /* Server */
156 sprintf (tmp, "Server: %s\r\n", SERVER_NAME);
157 add_line (buffer, tmp);
158
159 /* WWW-Authentificate */
160
161 return strlen (*buffer);
bb0468a5
LM
162}
163
cae06547 164int add_entity (char **buffer, char *entity, int size, char *type, char *encoding)
bb0468a5 165{
8a1d9e4a
LM
166 char tmp[BUFFER_SIZE] = {0};
167 int len = strlen (*buffer);
168
169 /* Allow */
170 /* Expires */
171 /* Last-Modified */
172
173 if (entity != NULL) {
174
175 /* Content-Encoding */
176 if (encoding != NULL) {
177 sprintf (tmp, "Content-Encoding: %s\r\n", encoding);
178 add_line (buffer, tmp);
179 }
180
181 /* Content-Length */
182 sprintf (tmp, "Content-Length: %d\r\n", size);
183 add_line (buffer, tmp);
184
185 /* Content-Type */
186 sprintf (tmp, "Content-Type: %s\r\n", type);
187 add_line (buffer, tmp);
188
189 add_line (buffer, "\r\n");
190
191 /* Entity */
192 len = strlen (*buffer);
193 *buffer = realloc (*buffer, len + size);
194 memcpy (*buffer + len, entity, size);
195 len += size;
196 }
197
bb0468a5
LM
198 return len;
199}
200
201/* error 400 */
202
203int error_400 (char **buffer)
204{
8a1d9e4a
LM
205 add_status_line (buffer, c400);
206 add_general_header (buffer);
207 add_response_header (buffer, NULL);
208
209 char *response = "<html><head><title>Error 400</title></head><body><p>Bad Request</p></body></html>";
cae06547 210 return add_entity (buffer, response, strlen (response), "text/html", "iso-8859-1");
8a1d9e4a
LM
211}
212
4baf6839
LM
213/* error 404 */
214
215int error_404 (char **buffer, char *uri)
216{
217 add_status_line (buffer, c404);
218 add_general_header (buffer);
219 add_response_header (buffer, uri);
220
221 char *response = "<html><head><title>Error 404</title></head><body><p>File not found</p></body></html>";
cae06547 222 return add_entity (buffer, response, strlen (response), "text/html", "iso-8859-1");
4baf6839
LM
223}
224
8a1d9e4a
LM
225/* response html */
226
227int response_html (char **buffer, char *location, char *response)
228{
50c7ef81
LM
229 int len = 0;
230 VERBOSE (DEBUG, PRINT ("add_status_line %d\n", len));
231 len = add_status_line (buffer, c200);
232 VERBOSE (DEBUG, PRINT ("add_general_header %d\n", len));
233 len = add_general_header (buffer);
234 VERBOSE (DEBUG, PRINT ("add_response_header %d\n", len));
235 len = add_response_header (buffer, location);
236
237 VERBOSE (DEBUG, PRINT ("add_entity %d\n", len));
cae06547 238 return add_entity (buffer, response, strlen (response), "text/html", "iso-8859-1");
bb0468a5
LM
239}
240
241/* trim string */
242
243char *trim (char *str)
244{
245 if (str != NULL) {
246 while ((*str == ' ') || (*str == '\t')) {
247 str++;
248 }
249 }
250 return str;
251}
252
253/* main HTTP processing */
254
4baf6839 255int processing (char *data, int len, char *root, char **pdata)
bb0468a5 256{
bb0468a5
LM
257 VERBOSE (DEBUG, PRINT ("Start processing\n"));
258
259 /* check method */
260 char *line = find_sequence (data, len, "\r\n", &data);
261 if (line == NULL) {
262 VERBOSE (WARNING, PRINT ("Unknown received data\n"));
263 if (pdata != NULL) {
264 *pdata = NULL;
265 }
266 return 0;
267 }
268 VERBOSE (DEBUG, PRINT ("Command line: '%s'\n", line));
269
270 char *method = strtok (line, " ");
271 char *uri = strtok (NULL, " ");
272 char *version = strtok (NULL, " ");
273 method_t type = not_supported_e;
274 if (strcmp (method, "GET") == 0) {
275 type = get_e;
276 } else if (strcmp ("HEAD", method) == 0) {
277 type = head_e;
278 } else if (strcmp ("POST", method) == 0) {
279 type = post_e;
280 } else {
281 VERBOSE (WARNING, PRINT ("Unkown method: %s\n", method));
bb0468a5
LM
282 return error_400 (pdata);
283 }
284 VERBOSE (INFO, PRINT ("%s %s (%s)\n", (type == get_e) ? "Get" : (type == head_e) ? "Head" : "Post", uri, version));
285
4baf6839 286 /* analyse uri */
6add28e9 287 char *filename = (char *)calloc (strlen (root) + strlen (uri) + 2, 1);
4baf6839
LM
288 //sprintf (filename, "%s%s%s", root, ((root[strlen (root) - 1] != '/') && (uri[0] != '/')) ? "/" : "", uri);
289 sprintf (filename, "%s/%s", root, uri);
290
bb0468a5
LM
291 /* check header */
292 header_t header = {0};
293 while (strcmp (line = find_sequence (data, len, "\r\n", &data), "") != 0) {
294 VERBOSE (DEBUG, PRINT ("Header line: '%s'\n", line));
295 char *field = strtok (line, ":");
296 char *value = trim (strtok (NULL, "\r"));
297 VERBOSE (DEBUG, PRINT ("Field: %s\nValue: %s\n", field, value));
298 if (*line == 0) {
299 break;
300 }
301
302 VERBOSE (DEBUG, PRINT ("Analyse field\n"));
303 if (strcmp (field, "Allow") == 0) {
304 header.allow = value;
305 } else if (strcmp (field, "Authorization") == 0) {
306 header.authorization = value;
307 } else if (strcmp (field, "Content-Encoding") == 0) {
308 header.content_encoding = value;
309 } else if (strcmp (field, "Content-Length") == 0) {
310 header.content_length = value;
311 } else if (strcmp (field, "Content-Type") == 0) {
312 header.content_type = value;
313 } else if (strcmp (field, "Date") == 0) {
314 header.date = value;
315 } else if (strcmp (field, "Expires") == 0) {
316 header.expires = value;
317 } else if (strcmp (field, "From") == 0) {
318 header.from = value;
319 } else if (strcmp (field, "If-Modified-Since") == 0) {
320 header.if_modified_since = value;
321 } else if (strcmp (field, "Last-Modified") == 0) {
322 header.last_modified = value;
323 } else if (strcmp (field, "Location") == 0) {
324 header.location = value;
325 } else if (strcmp (field, "Pragma") == 0) {
326 header.pragma = value;
327 } else if (strcmp (field, "Referer") == 0) {
328 header.referer = value;
329 } else if (strcmp (field, "Server") == 0) {
330 header.server = value;
331 } else if (strcmp (field, "User-Agent") == 0) {
332 header.user_agent = value;
333 } else if (strcmp (field, "WWW-Authenticate") == 0) {
334 header.www_authenticate = value;
335 } else {
336 VERBOSE (WARNING, PRINT ("Unknown header field: '%s'\n", field));
337 }
338 }
339 VERBOSE (DEBUG, print_header_values (&header));
340
bb0468a5 341 /* response */
4baf6839 342 char *buffer = NULL;
8a1d9e4a
LM
343 switch (type) {
344 case get_e:
6add28e9 345 VERBOSE (DEBUG, PRINT ("Read file %s\n", filename));
cae06547 346 len = readfile (&buffer, filename);
4baf6839
LM
347 if (len == 0) {
348 len = error_404 (pdata, "http://localhost/");
349 } else {
350 len = response_html (pdata, "http://localhost/", buffer);
351 free (buffer);
352 }
8a1d9e4a
LM
353 break;
354 case head_e:
355 break;
356 case post_e:
6add28e9 357 VERBOSE (DEBUG, PRINT ("Write file %s\n", filename));
8a1d9e4a
LM
358 break;
359 case not_supported_e:
360 break;
361 }
362
4baf6839 363 /* cleaning */
6add28e9
LM
364 VERBOSE (DEBUG, PRINT ("Cleaning\n"));
365 if (filename) {
366 VERBOSE (DEBUG, PRINT ("Cleaning filename\n"));
367 free (filename);
368 }
4baf6839 369
8a1d9e4a 370 return len;
bb0468a5
LM
371}
372
d0b0d52b 373/* vim: set ts=4 sw=4 et: */