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