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