adapt 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"
6
7#include "http.h"
8
8a1d9e4a
LM
9#define BUFFER_SIZE 128
10
bb0468a5
LM
11#define HTTP_VERSION "HTTP/1.0"
12#define SERVER_NAME "Webserver/0.0.1"
13
8a1d9e4a 14char *codes[15] = {
bb0468a5
LM
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
31typedef 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
38typedef enum {
39 not_supported_e = 0, get_e, head_e, post_e
40} method_t;
41
42typedef 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
63void 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
85char *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
8a1d9e4a 106int add_line (char **buffer, char *str)
bb0468a5 107{
8a1d9e4a
LM
108 int len = strlen (*buffer) + strlen (str) + 1;
109 *buffer = realloc (*buffer, len);
110 strcat (*buffer, str);
d0b0d52b
ML
111 return len;
112}
113
8a1d9e4a 114int add_status_line (char **buffer, code_t code)
bb0468a5 115{
8a1d9e4a
LM
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);
bb0468a5
LM
123}
124
8a1d9e4a 125int add_general_header (char **buffer)
bb0468a5 126{
8a1d9e4a
LM
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
139int 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);
bb0468a5
LM
154}
155
8a1d9e4a 156int add_entity (char **buffer, unsigned char *entity, int size, char *type, char *encoding)
bb0468a5 157{
8a1d9e4a
LM
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
bb0468a5
LM
190 return len;
191}
192
193/* error 400 */
194
195int error_400 (char **buffer)
196{
8a1d9e4a
LM
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
207int 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");
bb0468a5
LM
214}
215
216/* trim string */
217
218char *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
230int 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));
bb0468a5
LM
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 */
8a1d9e4a
LM
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;
bb0468a5
LM
335}
336
d0b0d52b 337/* vim: set ts=4 sw=4 et: */