best makefile
[webserver.git] / http.c
diff --git a/http.c b/http.c
index 6ce72c05854f61204aba636b0036b5d2f8e5978c..22b5cbcbbf901c169ca439bbcd45b97f837d1c8c 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1,6 +1,8 @@
 #include <malloc.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <unistd.h>
 
 #include "debug.h"
 #include "file.h"
@@ -40,10 +42,14 @@ typedef enum {
     not_supported_e = 0, get_e, head_e, post_e
 } method_t;
 
+typedef enum {
+    encoding_plain_e = 0, encoding_gzip_e, encoding_compress_e
+} encoding_t;
+
 typedef struct {
     char *allow;
     char *authorization;
-    char *content_encoding;
+    encoding_t content_encoding;
     char *content_length;
     char *content_type;
     char *date;
@@ -111,7 +117,14 @@ void print_header_values (header_t *header)
     printf ("Header values\n");
     if (header->allow) printf ("allow = '%s'\n", header->allow);
     if (header->authorization) printf ("authorization = '%s'\n", header->authorization);
-    if (header->content_encoding) printf ("content_encoding = '%s'\n", header->content_encoding);
+    if (header->content_encoding) {
+        printf ("content_encoding = ");
+        switch (header->content_encoding) {
+        case encoding_plain_e: printf ("plain\n"); break;
+        case encoding_gzip_e: printf ("gzip\n"); break;
+        case encoding_compress_e: printf ("compress\n"); break;
+        }
+    }
     if (header->content_length) printf ("content_length = '%s'\n", header->content_length);
     if (header->content_type) printf ("content_type = '%s'\n", header->content_type);
     if (header->date) printf ("date = '%s'\n", header->date);
@@ -221,7 +234,7 @@ int add_entity (char **buffer, char *entity, int size, char *type, char *encodin
 
         /* Content-Encoding */
         if (encoding != NULL) {
-            sprintf (tmp, "Content-Encoding: %sn", encoding);
+            sprintf (tmp, "Content-Encoding: %s", encoding);
             add_line (buffer, tmp);
         }
 
@@ -298,15 +311,25 @@ char *trim (char *str)
     return str;
 }
 
+/* creqte command */
+
+char *createcommand (char *format, char *name)
+{
+    char *command = (char *) calloc (strlen (format) + strlen (name) + 1, 1);
+    sprintf (command, format, name);
+    return command;
+}
+
 /* main HTTP processing */
 
 int processing (char *data, int len, conf_t *conf, char **pdata)
 {
+    char *saved_data = data;
     char location[BUFFER_SIZE] = {0};
     VERBOSE (DEBUG, PRINT ("Start processing\n"));
 
     /* check method */
-    char *line = find_sequence (data, len, "\r\n", &data);
+    char *line = find_sequence (data, len + data - saved_data, "\r\n", &data);
     if (line == NULL) {
         VERBOSE (WARNING, PRINT ("Unknown received data\n"));
         if (pdata != NULL) {
@@ -333,13 +356,15 @@ int processing (char *data, int len, conf_t *conf, char **pdata)
     VERBOSE (INFO, PRINT ("%s %s (%s)\n", (type == get_e) ? "Get" : (type == head_e) ? "Head" : "Post", uri, version));
 
     /* analyse uri */
-    char *filename = (char *)calloc (strlen (conf->root) + strlen (uri) + 2, 1);
+    char *filename = strtok (uri, "&");
+    char *variables = strtok (NULL, "\n");
+    char *path = (char *) calloc (strlen (conf->root) + strlen (filename) + 2, 1);
     //sprintf (filename, "%s%s%s", conf->root, ((conf->root[strlen (conf->root) - 1] != '/') && (uri[0] != '/')) ? "/" : "", uri);
-    sprintf (filename, "%s/%s", conf->root, uri);
+    sprintf (path, "%s/%s", conf->root, filename);
 
     /* check header */
     header_t header = {0};
-    while (strcmp (line = find_sequence (data, len, "\r\n", &data), "") != 0) {
+    while (strcmp (line = find_sequence (data, len + data - saved_data, "\r\n", &data), "") != 0) {
         VERBOSE (DEBUG, PRINT ("Header line: '%s'\n", line));
         char *field = strtok (line, ":");
         char *value = trim (strtok (NULL, "\r"));
@@ -347,65 +372,124 @@ int processing (char *data, int len, conf_t *conf, char **pdata)
         if (*line == 0) {
             break;
         }
-        
+
         VERBOSE (DEBUG, PRINT ("Analyse field\n"));
-        if (strcmp (field, "Allow") == 0) {
-            header.allow = value;
-        } else if (strcmp (field, "Authorization") == 0) {
-            header.authorization = value;
-        } else if (strcmp (field, "Content-Encoding") == 0) {
-            header.content_encoding = value;
-        } else if (strcmp (field, "Content-Length") == 0) {
-            header.content_length = value;
-        } else if (strcmp (field, "Content-Type") == 0) {
-            header.content_type = value;
-        } else if (strcmp (field, "Date") == 0) {
-            header.date = value;
-        } else if (strcmp (field, "Expires") == 0) {
-            header.expires = value;
-        } else if (strcmp (field, "From") == 0) {
-            header.from = value;
-        } else if (strcmp (field, "If-Modified-Since") == 0) {
-            header.if_modified_since = value;
-        } else if (strcmp (field, "Last-Modified") == 0) {
-            header.last_modified = value;
-        } else if (strcmp (field, "Location") == 0) {
-            header.location = value;
-        } else if (strcmp (field, "Pragma") == 0) {
-            header.pragma = value;
-        } else if (strcmp (field, "Referer") == 0) {
-            header.referer = value;
-        } else if (strcmp (field, "Server") == 0) {
-            header.server = value;
-        } else if (strcmp (field, "User-Agent") == 0) {
-            header.user_agent = value;
-        } else if (strcmp (field, "WWW-Authenticate") == 0) {
-            header.www_authenticate = value;
-        } else {
-            VERBOSE (WARNING, PRINT ("Unknown header field: '%s'\n", field));
-        }
+        if (strcmp (field, "Allow") == 0) { header.allow = value; }
+        else if (strcmp (field, "Authorization") == 0) { header.authorization = value; }
+        else if (strcmp (field, "Content-Encoding") == 0) {
+            if (strcmp (value, "x-gzip") == 0) {
+                header.content_encoding = encoding_gzip_e;
+            } else if (strcmp (value, "x-compress") == 0) {
+                header.content_encoding = encoding_compress_e;
+            } else {
+                VERBOSE (WARNING, PRINT ("Unknown content encoding: %s\n", value));
+            }
+        } else if (strcmp (field, "Content-Length") == 0) { header.content_length = value; }
+        else if (strcmp (field, "Content-Type") == 0) { header.content_type = value; }
+        else if (strcmp (field, "Date") == 0) { header.date = value; }
+        else if (strcmp (field, "Expires") == 0) { header.expires = value; }
+        else if (strcmp (field, "From") == 0) { header.from = value; }
+        else if (strcmp (field, "If-Modified-Since") == 0) { header.if_modified_since = value; }
+        else if (strcmp (field, "Last-Modified") == 0) { header.last_modified = value; }
+        else if (strcmp (field, "Location") == 0) { header.location = value; }
+        else if (strcmp (field, "Pragma") == 0) { header.pragma = value; }
+        else if (strcmp (field, "Referer") == 0) { header.referer = value; }
+        else if (strcmp (field, "Server") == 0) { header.server = value; }
+        else if (strcmp (field, "User-Agent") == 0) { header.user_agent = value; }
+        else if (strcmp (field, "WWW-Authenticate") == 0) { header.www_authenticate = value; }
+        else { VERBOSE (WARNING, PRINT ("Unknown header field: '%s'\n", field)); }
     }
     VERBOSE (DEBUG, print_header_values (&header));
 
+    /* body */
+    char *body = data;
+    char *newbody = NULL;
+    len -= saved_data - data;
+    if (len != (header.content_length ? atoi (header.content_length) : 0)) {
+        VERBOSE (WARNING, PRINT ("Incoherent size (%d <> %s)\n", len, header.content_length));
+    }
+    if (len > 0) {
+        int i;
+        char *fcomp= NULL;
+        char *fdecomp = NULL;
+        char *command = NULL;
+
+        switch (header.content_encoding) {
+        case encoding_plain_e:
+            break;
+
+        case encoding_gzip_e:
+            fcomp = tempname (conf->temp, ".gz");
+            writefile (fcomp, body, len);
+            command = createcommand ("gunzip %s", fcomp);
+            system (command);
+            fdecomp = strdup (fcomp);
+            for (i = strlen (fdecomp) - 1; i > 0; i--) {
+                if (fdecomp[i] == '.') {
+                    fdecomp[i] = 0;
+                    break;
+                }
+            }
+            len = readfile (&newbody, fdecomp);
+            break;
+
+        case encoding_compress_e:
+            fcomp = tempname (conf->temp, ".Z");
+            writefile (fcomp, body, len);
+            command = createcommand ("compress %s", fcomp);
+            system (command);
+            fdecomp = strdup (fcomp);
+            for (i = strlen (fdecomp) - 1; i > 0; i--) {
+                if (fdecomp[i] == '.') {
+                    fdecomp[i] = 0;
+                    break;
+                }
+            }
+            len = readfile (&newbody, fdecomp);
+            break;
+        }
+
+        if (fcomp) {
+            unlink (fcomp);
+            free (fcomp);
+        }
+        if (fdecomp) {
+            unlink (fdecomp);
+            free (fdecomp);
+        }
+        if (command) {
+            free (command);
+        }
+    }
+
     /* response */
     char *buffer = NULL;
+    FILE *fid = NULL;
     switch (type) {
     case get_e:
-        VERBOSE (DEBUG, PRINT ("Read file %s\n", filename));
-        len = readfile (&buffer, filename);
-        if (len == 0) {
+    case post_e: /* fall through */
+        VERBOSE (DEBUG, PRINT ("Read file %s\n", path));
+        len = readfile (&buffer, path);
+        if (len < 0) {
             sprintf (location, "http://%s/", conf->servername);
             len = error_404 (pdata, location);
         } else {
-            sprintf (location, "http://%s%s", conf->servername, filename);
+            sprintf (location, "http://%s%s", conf->servername, path);
             len = generic_response (pdata, location, buffer, len);
             free (buffer);
         }
         break;
     case head_e:
-        break;
-    case post_e:
-        VERBOSE (DEBUG, PRINT ("Write file %s\n", filename));
+        VERBOSE (DEBUG, PRINT ("Test file %s\n", path));
+        fid = fopen (path, "rb");
+        if (fid == NULL) {
+            sprintf (location, "http://%s/", conf->servername);
+            len = error_404 (pdata, location);
+        } else {
+            fclose (fid);
+            sprintf (location, "http://%s%s", conf->servername, path);
+            len = generic_response (pdata, location, NULL, 0);
+        }
         break;
     case not_supported_e:
         break;
@@ -413,9 +497,11 @@ int processing (char *data, int len, conf_t *conf, char **pdata)
 
     /* cleaning */
     VERBOSE (DEBUG, PRINT ("Cleaning\n"));
-    if (filename) {
-        VERBOSE (DEBUG, PRINT ("Cleaning filename\n"));
-        free (filename);
+    if (path) {
+        free (path);
+    }
+    if (newbody) {
+        free (newbody);
     }
 
     return len;