12 #define BUFFER_SIZE 128
14 #define HTTP_VERSION "HTTP/1.0"
15 #define SERVER_NAME "Webserver/0.0.1"
22 "301 Moved Permanently",
23 "302 Moved Temporarily",
29 "500 Internal Server Error",
30 "501 Not Implemented",
32 "503 Service Unavailable"};
35 c200
= 0, c201
, c202
, c204
,
36 c301
, c302
, c304
, c400
,
37 c401
, c403
, c404
, c500
,
42 not_supported_e
= 0, get_e
, head_e
, post_e
46 encoding_plain_e
= 0, encoding_gzip_e
, encoding_compress_e
52 encoding_t content_encoding
;
58 char *if_modified_since
;
65 char *www_authenticate
;
76 mime_t mimes
[NB_MIMES
] = {
77 {"js", "application/javascript", "iso-8859-1"},
78 {"css", "text/css", "iso-8859-1"},
79 {"htm", "text/html", "iso-8859-1"},
80 {"html", "text/html", "iso-8859-1"},
81 {"png", "image/png", NULL
},
82 {"jpeg", "image/jpeg", NULL
},
83 {"jpg", "image/jpeg", NULL
},
84 {"txt", "text/plain", "iso-8859-1"}
89 mime_t
*find_mime_type (char *filename
)
92 char *ext
= filename
+ strlen (filename
);
93 while (--ext
> filename
) {
98 if (ext
== filename
) {
104 for (i
= 0; i
< NB_MIMES
; i
++) {
105 if (strcmp (ext
, (mimes
+ i
)->ext
) == 0) {
113 /* print header values */
115 void print_header_values (header_t
*header
)
117 printf ("Header values\n");
118 if (header
->allow
) printf ("allow = '%s'\n", header
->allow
);
119 if (header
->authorization
) printf ("authorization = '%s'\n", header
->authorization
);
120 if (header
->content_encoding
) {
121 printf ("content_encoding = ");
122 switch (header
->content_encoding
) {
123 case encoding_plain_e
: printf ("plain\n"); break;
124 case encoding_gzip_e
: printf ("gzip\n"); break;
125 case encoding_compress_e
: printf ("compress\n"); break;
128 if (header
->content_length
) printf ("content_length = '%s'\n", header
->content_length
);
129 if (header
->content_type
) printf ("content_type = '%s'\n", header
->content_type
);
130 if (header
->date
) printf ("date = '%s'\n", header
->date
);
131 if (header
->expires
) printf ("expires = '%s'\n", header
->expires
);
132 if (header
->from
) printf ("from = '%s'\n", header
->from
);
133 if (header
->if_modified_since
) printf ("if_modified_since = '%s'\n", header
->if_modified_since
);
134 if (header
->last_modified
) printf ("last_modified = '%s'\n", header
->last_modified
);
135 if (header
->location
) printf ("location = '%s'\n", header
->location
);
136 if (header
->pragma
) printf ("pragma = '%s'\n", header
->pragma
);
137 if (header
->referer
) printf ("referer = '%s'\n", header
->referer
);
138 if (header
->server
) printf ("server = '%s'\n", header
->server
);
139 if (header
->user_agent
) printf ("user_agent = '%s'\n", header
->user_agent
);
140 if (header
->www_authenticate
) printf ("www_authenticate = '%s'\n", header
->www_authenticate
);
145 char *find_sequence (char *data
, int len
, char *seq
, char **pdata
)
148 int size
= strlen (seq
);
151 for (i
= 0; i
< len
- size
+ 1; i
++) {
152 if (strncmp (data
+ i
, seq
, size
) == 0) {
155 *pdata
= data
+ i
+ size
;
164 /* response entity */
166 int add_line (char **buffer
, char *str
)
168 VERBOSE (DEBUG
, PRINT ("add line: %s\n", str
));
169 int len
= ((*buffer
) ? strlen (*buffer
) : 0) + strlen (str
) + 3;
170 VERBOSE (DEBUG
, PRINT ("len: %d\n", len
));
172 *buffer
= (char *)realloc (*buffer
, len
);
174 *buffer
= (char *)calloc (len
, 1);
176 strcat (*buffer
, str
);
177 strcat (*buffer
, "\r\n");
181 int add_status_line (char **buffer
, code_t code
)
183 char tmp
[BUFFER_SIZE
] = {0};
186 sprintf (tmp
, "%s %s", HTTP_VERSION
, codes
[code
]);
187 add_line (buffer
, tmp
);
189 return strlen (*buffer
);
192 int add_general_header (char **buffer
)
194 char tmp
[BUFFER_SIZE
] = {0};
197 time_t ts
= time (NULL
);
198 sprintf (tmp
, "Date: %s", ctime (&ts
));
199 tmp
[strlen (tmp
) - 1] = 0; // remove last \n
200 add_line (buffer
, tmp
);
204 return strlen (*buffer
);
207 int add_response_header (char **buffer
, char *uri
)
209 char tmp
[BUFFER_SIZE
] = {0};
212 sprintf (tmp
, "Location: %s", uri
);
213 add_line (buffer
, tmp
);
216 sprintf (tmp
, "Server: %s", SERVER_NAME
);
217 add_line (buffer
, tmp
);
219 /* WWW-Authentificate */
221 return strlen (*buffer
);
224 int add_entity (char **buffer
, char *entity
, int size
, char *type
, char *encoding
)
226 char tmp
[BUFFER_SIZE
] = {0};
227 int len
= strlen (*buffer
);
233 if (entity
!= NULL
) {
235 /* Content-Encoding */
236 if (encoding
!= NULL
) {
237 sprintf (tmp
, "Content-Encoding: %s", encoding
);
238 add_line (buffer
, tmp
);
242 sprintf (tmp
, "Content-Length: %d", size
);
243 add_line (buffer
, tmp
);
246 sprintf (tmp
, "Content-Type: %s", type
);
247 add_line (buffer
, tmp
);
249 add_line (buffer
, "");
252 len
= strlen (*buffer
);
253 *buffer
= realloc (*buffer
, len
+ size
);
254 memcpy (*buffer
+ len
, entity
, size
);
263 int error_400 (char **buffer
)
265 add_status_line (buffer
, c400
);
266 add_general_header (buffer
);
267 add_response_header (buffer
, NULL
);
269 char *response
= "<html><head><title>Error 400</title></head><body><p>Bad Request</p></body></html>";
270 return add_entity (buffer
, response
, strlen (response
), "text/html", "iso-8859-1");
275 int error_404 (char **buffer
, char *uri
)
277 add_status_line (buffer
, c404
);
278 add_general_header (buffer
);
279 add_response_header (buffer
, uri
);
281 char *response
= "<html><head><title>Error 404</title></head><body><p>File not found</p></body></html>";
282 return add_entity (buffer
, response
, strlen (response
), "text/html", "iso-8859-1");
285 /* generic response */
287 int generic_response (char **buffer
, char *location
, char *response
, int size
)
290 VERBOSE (DEBUG
, PRINT ("add_status_line %d\n", len
));
291 len
= add_status_line (buffer
, c200
);
292 VERBOSE (DEBUG
, PRINT ("add_general_header %d\n", len
));
293 len
= add_general_header (buffer
);
294 VERBOSE (DEBUG
, PRINT ("add_response_header %d\n", len
));
295 len
= add_response_header (buffer
, location
);
296 mime_t
*mime
= find_mime_type (location
);
298 VERBOSE (DEBUG
, PRINT ("add_entity %d\n", len
));
299 return add_entity (buffer
, response
, size
, mime
->type
, mime
->charset
);
304 char *trim (char *str
)
307 while ((*str
== ' ') || (*str
== '\t')) {
316 char *createcommand (char *format
, char *name
)
318 char *command
= (char *) calloc (strlen (format
) + strlen (name
) + 1, 1);
319 sprintf (command
, format
, name
);
323 /* main HTTP processing */
325 int processing (char *data
, int len
, conf_t
*conf
, char **pdata
)
327 char *saved_data
= data
;
328 char location
[BUFFER_SIZE
] = {0};
329 VERBOSE (DEBUG
, PRINT ("Start processing\n"));
332 char *line
= find_sequence (data
, len
+ data
- saved_data
, "\r\n", &data
);
334 VERBOSE (WARNING
, PRINT ("Unknown received data\n"));
340 VERBOSE (DEBUG
, PRINT ("Command line: '%s'\n", line
));
342 char *method
= strtok (line
, " ");
343 char *uri
= strtok (NULL
, " ");
344 char *version
= strtok (NULL
, " ");
345 method_t type
= not_supported_e
;
346 if (strcmp (method
, "GET") == 0) {
348 } else if (strcmp ("HEAD", method
) == 0) {
350 } else if (strcmp ("POST", method
) == 0) {
353 VERBOSE (WARNING
, PRINT ("Unkown method: %s\n", method
));
354 return error_400 (pdata
);
356 VERBOSE (INFO
, PRINT ("%s %s (%s)\n", (type
== get_e
) ? "Get" : (type
== head_e
) ? "Head" : "Post", uri
, version
));
359 char *filename
= strtok (uri
, "&");
360 char *variables
= strtok (NULL
, "\n");
361 char *path
= (char *) calloc (strlen (conf
->root
) + strlen (filename
) + 2, 1);
362 //sprintf (filename, "%s%s%s", conf->root, ((conf->root[strlen (conf->root) - 1] != '/') && (uri[0] != '/')) ? "/" : "", uri);
363 sprintf (path
, "%s/%s", conf
->root
, filename
);
366 header_t header
= {0};
367 while (strcmp (line
= find_sequence (data
, len
+ data
- saved_data
, "\r\n", &data
), "") != 0) {
368 VERBOSE (DEBUG
, PRINT ("Header line: '%s'\n", line
));
369 char *field
= strtok (line
, ":");
370 char *value
= trim (strtok (NULL
, "\r"));
371 VERBOSE (DEBUG
, PRINT ("Field: %s\nValue: %s\n", field
, value
));
376 VERBOSE (DEBUG
, PRINT ("Analyse field\n"));
377 if (strcmp (field
, "Allow") == 0) { header
.allow
= value
; }
378 else if (strcmp (field
, "Authorization") == 0) { header
.authorization
= value
; }
379 else if (strcmp (field
, "Content-Encoding") == 0) {
380 if (strcmp (value
, "x-gzip") == 0) {
381 header
.content_encoding
= encoding_gzip_e
;
382 } else if (strcmp (value
, "x-compress") == 0) {
383 header
.content_encoding
= encoding_compress_e
;
385 VERBOSE (WARNING
, PRINT ("Unknown content encoding: %s\n", value
));
387 } else if (strcmp (field
, "Content-Length") == 0) { header
.content_length
= value
; }
388 else if (strcmp (field
, "Content-Type") == 0) { header
.content_type
= value
; }
389 else if (strcmp (field
, "Date") == 0) { header
.date
= value
; }
390 else if (strcmp (field
, "Expires") == 0) { header
.expires
= value
; }
391 else if (strcmp (field
, "From") == 0) { header
.from
= value
; }
392 else if (strcmp (field
, "If-Modified-Since") == 0) { header
.if_modified_since
= value
; }
393 else if (strcmp (field
, "Last-Modified") == 0) { header
.last_modified
= value
; }
394 else if (strcmp (field
, "Location") == 0) { header
.location
= value
; }
395 else if (strcmp (field
, "Pragma") == 0) { header
.pragma
= value
; }
396 else if (strcmp (field
, "Referer") == 0) { header
.referer
= value
; }
397 else if (strcmp (field
, "Server") == 0) { header
.server
= value
; }
398 else if (strcmp (field
, "User-Agent") == 0) { header
.user_agent
= value
; }
399 else if (strcmp (field
, "WWW-Authenticate") == 0) { header
.www_authenticate
= value
; }
400 else { VERBOSE (WARNING
, PRINT ("Unknown header field: '%s'\n", field
)); }
402 VERBOSE (DEBUG
, print_header_values (&header
));
406 char *newbody
= NULL
;
407 len
-= saved_data
- data
;
408 if (len
!= (header
.content_length
? atoi (header
.content_length
) : 0)) {
409 VERBOSE (WARNING
, PRINT ("Incoherent size (%d <> %s)\n", len
, header
.content_length
));
414 char *fdecomp
= NULL
;
415 char *command
= NULL
;
417 switch (header
.content_encoding
) {
418 case encoding_plain_e
:
421 case encoding_gzip_e
:
422 fcomp
= tempname (conf
->temp
, ".gz");
423 writefile (fcomp
, body
, len
);
424 command
= createcommand ("gunzip %s", fcomp
);
426 fdecomp
= strdup (fcomp
);
427 for (i
= strlen (fdecomp
) - 1; i
> 0; i
--) {
428 if (fdecomp
[i
] == '.') {
433 len
= readfile (&newbody
, fdecomp
);
436 case encoding_compress_e
:
437 fcomp
= tempname (conf
->temp
, ".Z");
438 writefile (fcomp
, body
, len
);
439 command
= createcommand ("compress %s", fcomp
);
441 fdecomp
= strdup (fcomp
);
442 for (i
= strlen (fdecomp
) - 1; i
> 0; i
--) {
443 if (fdecomp
[i
] == '.') {
448 len
= readfile (&newbody
, fdecomp
);
470 case post_e
: /* fall through */
471 VERBOSE (DEBUG
, PRINT ("Read file %s\n", path
));
472 len
= readfile (&buffer
, path
);
474 sprintf (location
, "http://%s/", conf
->servername
);
475 len
= error_404 (pdata
, location
);
477 sprintf (location
, "http://%s%s", conf
->servername
, path
);
478 len
= generic_response (pdata
, location
, buffer
, len
);
483 VERBOSE (DEBUG
, PRINT ("Test file %s\n", path
));
484 fid
= fopen (path
, "rb");
486 sprintf (location
, "http://%s/", conf
->servername
);
487 len
= error_404 (pdata
, location
);
490 sprintf (location
, "http://%s%s", conf
->servername
, path
);
491 len
= generic_response (pdata
, location
, NULL
, 0);
494 case not_supported_e
:
499 VERBOSE (DEBUG
, PRINT ("Cleaning\n"));
510 /* vim: set ts=4 sw=4 et: */