From 10e78d6a1c55e13c10386abc2375206318a521a2 Mon Sep 17 00:00:00 2001
From: Abhigna Nagaraj <abhigna.n4@gmail.com>
Date: Thu, 5 Apr 2012 01:45:53 +0530
Subject: [PATCH] HTTP: Add virtualhost alias feature

Add virtualhost alias feature from Ticket #55.
---
 src/include/mk_config.h |    7 ++++
 src/mk_config.c         |  101 +++++++++++++++++++++++++++++++++++++++++++++
 src/mk_http.c           |  104 ++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 189 insertions(+), 23 deletions(-)

diff --git a/src/include/mk_config.h b/src/include/mk_config.h
index 606e602..e98b758 100644
--- a/src/include/mk_config.h
+++ b/src/include/mk_config.h
@@ -140,10 +140,17 @@ struct server_config
 
 struct server_config *config;
 
+struct path_alias {
+    mk_pointer source_path;
+    mk_pointer dest_path;
+    struct mk_list _head;
+};
+
 struct host
 {
     char *file;                   /* configuration file */
     struct mk_list server_names;  /* host names (a b c...) */
+    struct mk_list path_aliases;  /* Source Dest mappings */
 
     mk_pointer documentroot;
 
diff --git a/src/mk_config.c b/src/mk_config.c
index f7c9a1e..bfdb298 100644
--- a/src/mk_config.c
+++ b/src/mk_config.c
@@ -549,6 +549,54 @@ void mk_config_read_hosts(char *path)
     closedir(dir);
 }
 
+int mk_config_parse_escaped_val(char *s, char **res, char **cont){
+    /* Only Whitespace is escaped */
+    int e_count = 0;
+    char *beg_s, *end_s, *cpy_res;
+
+    /* Skip initial whitespaces */
+    while(*s==' ' || *s== '\t')
+          s++;
+    beg_s = s;
+
+    if(*s == '\0')
+        /* Empty string */
+        return -1;
+
+    s++;
+    while(*s!='\0'){
+        /* Escaped whitespaces */
+        if(*s == '\\')
+        {
+            s++;
+            if( *s == ' ' || *s == '\t' )
+                e_count++;
+        }
+        else if(*s == ' ' || *s == '\t' ){
+            break;
+        }
+        s++;
+    }
+    end_s = s;
+    *cont = end_s;
+
+    cpy_res = mk_mem_malloc((end_s - beg_s + 1) - e_count);
+    *res = cpy_res;
+
+    for(s=beg_s; s!=end_s; s++){
+        if(*s == '\\')
+        {
+           s++;
+           if( *s == ' ' || *s == '\t')
+                *cpy_res++ = *s;
+        }
+        else
+            *cpy_res++ = *s;
+    }
+    *cpy_res = '\0';
+    return 0;
+}
+
 struct host *mk_config_get_host(char *path)
 {
     unsigned long len = 0;
@@ -556,9 +604,11 @@ struct host *mk_config_get_host(char *path)
     struct stat checkdir;
     struct host *host;
     struct host_alias *new_alias;
+    struct path_alias *new_path_alias;
     struct mk_config *cnf;
     struct mk_config_section *section;
     struct mk_string_line *entry;
+    struct mk_config_entry *pa_entry;
     struct mk_list *head, *list;
 
     /* Read configuration file */
@@ -606,6 +656,48 @@ struct host *mk_config_get_host(char *path)
     mk_mem_free(host_low);
     mk_string_split_free(list);
 
+    /* For path aliases */
+    mk_list_init(&host->path_aliases);
+
+    mk_list_foreach(head, &section->entries) {
+        pa_entry = mk_list_entry(head, struct mk_config_entry, _head);
+
+        if (strcasecmp(pa_entry->key, "Alias") == 0) {
+            char *cont, *val;
+            char *source,* dest;
+            int res;
+
+            new_path_alias = mk_mem_malloc_z(sizeof(struct path_alias));
+            val = pa_entry->val;
+            res = mk_config_parse_escaped_val(val,
+                                &source, &cont);
+            if(res == 0) {
+                res = mk_config_parse_escaped_val(cont,
+                            &dest, &cont);
+                if(res == 0) {
+                    mk_pointer_set(&(new_path_alias->source_path), source);
+                    mk_pointer_set(&(new_path_alias->dest_path), dest);
+                    /* Skip trailing spaces */
+                    while(*cont == ' ' || *cont == '\t')
+                        cont++;
+                }
+            }
+
+            if(res == -1 || *cont != '\0')
+            /* Check if this is the end of string */
+                mk_err("Skipping Alias in %s", path);
+            else if(source[0] !='/' || dest[0] !='/')
+            /* Make sure all begin with a '/'  */
+                mk_err("Skipping Alias in %s", path);
+            else if (stat(dest, &checkdir) == -1)
+                mk_err("Invalid path in Alias %s", dest);
+            else {
+                mk_list_add(&new_path_alias->_head, &host->path_aliases);
+                MK_TRACE("Setup Alias %s to %s", source, dest);
+            }
+        }
+    }
+
     /* document root handled by a mk_pointer */
     host->documentroot.data = mk_config_section_getval(section,
                                                        "DocumentRoot",
@@ -739,6 +831,7 @@ void mk_config_host_free_all()
 {
     struct host *host;
     struct host_alias *host_alias;
+    struct path_alias *path_alias;
     struct mk_list *head_host;
     struct mk_list *head_alias;
     struct mk_list *tmp1, *tmp2;
@@ -757,6 +850,14 @@ void mk_config_host_free_all()
             mk_mem_free(host_alias);
         }
 
+        /* Free path aliases */
+        mk_list_foreach_safe(head_alias, tmp2, &host->path_aliases) {
+            path_alias = mk_list_entry(head_alias, struct path_alias, _head);
+            mk_list_del(&path_alias->_head);
+            mk_pointer_free(&path_alias->source_path);
+            mk_pointer_free(&path_alias->dest_path);
+        }
+
         mk_pointer_free(&host->documentroot);
         mk_mem_free(host->host_signature);
         mk_pointer_free(&host->header_host_signature);
diff --git a/src/mk_http.c b/src/mk_http.c
index d79c7ef..61a1fb2 100644
--- a/src/mk_http.c
+++ b/src/mk_http.c
@@ -137,14 +137,65 @@ mk_pointer mk_http_protocol_check_str(int protocol)
     return mk_http_protocol_null_p;
 }
 
+int mk_map_path_alias(mk_pointer *str, mk_pointer *src, mk_pointer *des,
+       mk_pointer *res){
+    /* str -> original path
+     * src -> path to replace(alias)
+     * des -> path to replace with
+     * res -> store result path
+     */
+    char *cpy;
+    size_t nbytes;
+
+    if(!str->data)
+        return -1;
+
+    if(str->len < src->len)
+        return -1;
+
+    /* If it does not begin with src dont map */
+    if(memcmp(str->data, src->data, src->len)!=0)
+        return -1;
+
+    res->len = str->len + des->len - src->len;
+    cpy = res->data = mk_mem_malloc_z(res->len+1);
+
+    nbytes = des->len;
+    memcpy(cpy, des->data, nbytes);
+    cpy += des->len;
+    nbytes = str->len - src->len;
+    memcpy(cpy, str->data + src->len, nbytes);
+    res->data[res->len] = '\0';
+
+    return 0;
+}
+
 int mk_http_init(struct client_session *cs, struct session_request *sr)
 {
     int ret;
     int bytes = 0;
     struct mimetype *mime;
-    
+
+    /* Path Alias stuff */
+    struct mk_list *head_pa;
+    struct path_alias *pa_entry;
+    mk_pointer aliased_path;
+    struct mk_list *pa_lst = &(sr->host_conf->path_aliases);
+
     MK_TRACE("HTTP Protocol Init");
 
+    mk_list_foreach(head_pa, pa_lst) {
+        pa_entry = mk_list_entry(head_pa, struct path_alias, _head);
+        ret = mk_map_path_alias(&(sr->uri_processed), &(pa_entry->source_path),
+                &(pa_entry->dest_path), &aliased_path);
+        if(ret == 0)
+        /* Matched an alias */
+        {
+            MK_TRACE("Matched alias %s", aliased_path.data);
+            break;
+        }
+    }
+
     /* Request to root path of the virtualhost in question */
     if (sr->uri_processed.len == 1 && sr->uri_processed.data[0] == '/') {
         sr->real_path.data = sr->host_conf->documentroot.data;
@@ -153,30 +204,37 @@ int mk_http_init(struct client_session *cs, struct session_request *sr)
 
     /* Compose real path */
     if (sr->user_home == MK_FALSE) {
-        int len;
-
-        len = sr->host_conf->documentroot.len + sr->uri_processed.len;
-        if (len < MK_PATH_BASE) {
-            memcpy(sr->real_path_static, 
-                   sr->host_conf->documentroot.data,
-                   sr->host_conf->documentroot.len);
-            memcpy(sr->real_path_static + sr->host_conf->documentroot.len,
-                   sr->uri_processed.data,
-                   sr->uri_processed.len);
-            sr->real_path_static[len] = '\0';
-            sr->real_path.data = sr->real_path_static;
-            sr->real_path.len = len;
+        if(ret == 0){
+            /* Assign mapped path using alias */
+            sr->real_path.data = aliased_path.data;
+            sr->real_path.len = aliased_path.len;
         }
         else {
-            ret = mk_buffer_cat(&sr->real_path, 
-                                sr->host_conf->documentroot.data,
-                                sr->host_conf->documentroot.len,
-                                sr->uri_processed.data,
-                                sr->uri_processed.len);
-        
-            if (ret < 0) {
-                MK_TRACE("Error composing real path");
-                return EXIT_ERROR;
+           /* Normal path using documentroot */
+            int len;
+            len = sr->host_conf->documentroot.len + sr->uri_processed.len;
+            if (len < MK_PATH_BASE) {
+                memcpy(sr->real_path_static, 
+                    sr->host_conf->documentroot.data,
+                    sr->host_conf->documentroot.len);
+                memcpy(sr->real_path_static + sr->host_conf->documentroot.len,
+                    sr->uri_processed.data,
+                    sr->uri_processed.len);
+                sr->real_path_static[len] = '\0';
+                sr->real_path.data = sr->real_path_static;
+                sr->real_path.len = len;
+            }
+            else {
+                ret = mk_buffer_cat(&sr->real_path, 
+                                    sr->host_conf->documentroot.data,
+                                    sr->host_conf->documentroot.len,
+                                    sr->uri_processed.data,
+                                    sr->uri_processed.len);
+
+                if (ret < 0) {
+                    MK_TRACE("Error composing real path");
+                    return EXIT_ERROR;
+                }
             }
         }
     }
-- 
1.7.9.5

