You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by "Ralf S. Engelschall" <rs...@engelschall.com> on 1998/02/12 16:18:56 UTC

[PATCH] New RewriteMap types for mod_rewrite

Apache as a Reverse Proxy and 
Apache does Virtual Hosting without <VirtualHost>
-------------------------------------------------

The following patch superseeds the recently posted patch which just introduced
the int:toupper and int:tolower RewriteMap types, because for Reverse Proxing
a rnd:<file> type was needed and both patches change the same source part.

What it does:

   - adds another new RewriteMap type rnd:<file> which is
     equivalent to the txt:<file> type but with a special
     post-processing for the looked up value: It is parsed into
     alternatives according to "|" chars and then a particular
     alternative is choosen randomly. This is an essential
     functionality needed for balancing between backend-servers
     when using Apache as a Reverse Proxy. The looked up value
     here is a list of servers. 

     It is used like this:
       RewriteMap server rnd:/u/rse/work/wt/ap/apache-rproxy.tab
       RewriteRule  ^/(.*\.(phtml|cgi))$  http://${server:dynamic}/$1 [P,L]
       RewriteRule  ^/(.*)$               http://${server:static}/$1  [P,L]

     with /u/rse/work/wt/ap/apache-rproxy.tab reading:
       static    server1|server2|server3|server4
       dynamic   server5|server6

     (The complete setup which is needed to let Apache act as a full-featured
     Reverse Proxy is also available, but because I've developed it for an
     WEBTechniques article I cannot publically post it here. When someone is
     interested, I can post it to apache-core of course.)
    
   - adds int:tolower and int:toupper Internal Function based
     rewriting maps which can be used to map hostnames to a fixed
     case when using mod_rewrite to do mass virtual hosting
     without using 1001 <VirtualHost> section.

Greetings,
                                       Ralf S. Engelschall
                                       rse@engelschall.com
                                       www.engelschall.com

Index: src/modules/standard/mod_rewrite.c
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/modules/standard/mod_rewrite.c,v
retrieving revision 1.66
diff -u -r1.66 mod_rewrite.c
--- mod_rewrite.c	1998/02/02 22:33:40	1.66
+++ mod_rewrite.c	1998/02/12 14:31:04
@@ -93,6 +93,7 @@
 #include <time.h>
 #include <signal.h>
 #include <errno.h>
+#include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #ifdef WIN32
@@ -435,11 +436,17 @@
     new = push_array(sconf->rewritemaps);
 
     new->name = a1;
+    new->func = NULL;
     if (strncmp(a2, "txt:", 4) == 0) {
         new->type      = MAPTYPE_TXT;
         new->datafile  = a2+4;
         new->checkfile = a2+4;
     }
+    else if (strncmp(a2, "rnd:", 4) == 0) {
+        new->type      = MAPTYPE_RND;
+        new->datafile  = a2+4;
+        new->checkfile = a2+4;
+    }
     else if (strncmp(a2, "dbm:", 4) == 0) {
 #ifdef HAS_NDBM_LIB
         new->type      = MAPTYPE_DBM;
@@ -455,6 +462,18 @@
         new->datafile = a2+4;
         new->checkfile = a2+4;
     }
+    else if (strncmp(a2, "int:", 4) == 0) {
+        new->type      = MAPTYPE_INT;
+        new->datafile  = NULL;
+        new->checkfile = NULL;
+        if (strcmp(a2+4, "tolower") == 0) 
+            new->func = rewrite_mapfunc_tolower;
+        else if (strcmp(a2+4, "toupper") == 0)
+            new->func = rewrite_mapfunc_toupper;
+        else if (sconf->state == ENGINE_ENABLED)
+            return pstrcat(cmd->pool, "RewriteMap: internal map not found:",
+                           a2+4, NULL);     
+    }
     else {
         new->type      = MAPTYPE_TXT;
         new->datafile  = a2;
@@ -2499,6 +2518,52 @@
                                s->name, key);
                 }
             }
+            else if (s->type == MAPTYPE_INT) {
+                if ((value = lookup_map_internal(r, s->func, key)) != NULL) {
+                    rewritelog(r, 5, "map lookup OK: map=%s key=%s -> val=%s", 
+                               s->name, key, value);
+                    return value;
+                }
+                else {
+                    rewritelog(r, 5, "map lookup FAILED: map=%s key=%s", 
+                               s->name, key);
+                }
+            }
+            else if (s->type == MAPTYPE_RND) {
+                if (stat(s->checkfile, &st) == -1) {
+                    aplog_error(APLOG_MARK, APLOG_ERR, r->server,
+                                "mod_rewrite: can't access text RewriteMap "
+                                "file %s", s->checkfile);
+                    rewritelog(r, 1,
+                               "can't open RewriteMap file, see error log");
+                    return NULL;
+                }
+                value = get_cache_string(cachep, s->name, CACHEMODE_TS, 
+                                         st.st_mtime, key);
+                if (value == NULL) {
+                    rewritelog(r, 6, "cache lookup FAILED, forcing new "
+                               "map lookup");
+                    if ((value = 
+                         lookup_map_txtfile(r, s->datafile, key)) != NULL) {
+                        rewritelog(r, 5, "map lookup OK: map=%s key=%s[txt] "
+                                   "-> val=%s", s->name, key, value);
+                        set_cache_string(cachep, s->name, CACHEMODE_TS, 
+                                         st.st_mtime, key, value);
+                    }
+                    else {
+                        rewritelog(r, 5, "map lookup FAILED: map=%s[txt] "
+                                   "key=%s", s->name, key);
+                        return NULL;
+                    }
+                }
+                else {
+                    rewritelog(r, 5, "cache lookup OK: map=%s[txt] key=%s "
+                               "-> val=%s", s->name, key, value);
+                }
+                value = select_random_value_part(r, value);
+                rewritelog(r, 5, "randomly choosen the subvalue `%s'", value);
+                return value;
+            }
         }
     }
     return NULL;
@@ -2605,7 +2670,87 @@
         return pstrdup(r->pool, buf);
 }
 
+static char *lookup_map_internal(request_rec *r,
+                                 char *(*func)(request_rec *, char *),
+                                 char *key)
+{
+    /* currently we just let the function convert 
+       the key to a corresponding value */
+    return func(r, key);
+}
+
+static char *rewrite_mapfunc_toupper(request_rec *r, char *key)
+{
+    char *value, *cp;
+
+    for (cp = value = pstrdup(r->pool, key); cp != NULL && *cp != '\0'; cp++)
+        *cp = toupper(*cp);
+    return value;
+}
+
+static char *rewrite_mapfunc_tolower(request_rec *r, char *key)
+{
+    char *value, *cp;
+
+    for (cp = value = pstrdup(r->pool, key); cp != NULL && *cp != '\0'; cp++)
+        *cp = tolower(*cp);
+    return value;
+}
+
+static int rewrite_rand_init_done = 0;
 
+void rewrite_rand_init(void)
+{
+    if (!rewrite_rand_init_done) {
+        srand((unsigned)(getpid()));
+        rewrite_rand_init_done = 1;
+    }
+    return;
+}
+
+int rewrite_rand(int l, int h)
+{
+    int i;
+    char buf[50];
+
+    rewrite_rand_init();
+    sprintf(buf, "%.0f", (((double)rand()/RAND_MAX)*(h-l)));
+    i = atoi(buf)+1;
+    if (i < l) i = l;
+    if (i > h) i = h;
+    return i;
+}
+
+static char *select_random_value_part(request_rec *r, char *value)
+{
+    char *buf;
+    int n, i, k;
+
+    /*  count number of distinct values  */
+    for (n = 1, i = 0; value[i] != '\0'; i++)
+        if (value[i] == '|')
+            n++;
+
+    /*  when only one value we have no option to choose  */
+    if (n == 1)
+        return value;
+
+    /*  else randomly select one  */
+    k = rewrite_rand(1, n);
+
+    /*  and grep it out  */
+    for (n = 1, i = 0; value[i] != '\0'; i++) {
+        if (n == k)
+            break;
+        if (value[i] == '|')
+            n++;
+    }
+    buf = pstrdup(r->pool, &value[i]);
+    for (i = 0; buf[i] != '\0' && buf[i] != '|'; i++)
+        ;
+    buf[i] = '\0';
+    return buf;
+}
 
 
 /*
@@ -2912,7 +3057,7 @@
                 continue;
             }
         }
-	outp = ap_cpystrn(outp, cp, endp - outp);
+    outp = ap_cpystrn(outp, cp, endp - outp);
         break;
     }
     return expanded ? pstrdup(r->pool, output) : str;
@@ -3010,7 +3155,7 @@
         result = r->server->server_admin;
     }
     else if (strcasecmp(var, "SERVER_NAME") == 0) {
-	result = get_server_name(r);
+    result = get_server_name(r);
     }
     else if (strcasecmp(var, "SERVER_PORT") == 0) {
         ap_snprintf(resultbuf, sizeof(resultbuf), "%u", get_server_port(r));
Index: src/modules/standard/mod_rewrite.h
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/modules/standard/mod_rewrite.h,v
retrieving revision 1.36
diff -u -r1.36 mod_rewrite.h
--- mod_rewrite.h	1998/01/07 16:46:56	1.36
+++ mod_rewrite.h	1998/02/12 14:27:23
@@ -184,6 +184,8 @@
 #define MAPTYPE_TXT                 1<<0
 #define MAPTYPE_DBM                 1<<1
 #define MAPTYPE_PRG                 1<<2
+#define MAPTYPE_INT                 1<<3
+#define MAPTYPE_RND                 1<<4
 
 #define ENGINE_DISABLED             1<<0
 #define ENGINE_ENABLED              1<<1
@@ -228,8 +230,10 @@
     char *datafile;                /* filename for map data files */
     char *checkfile;               /* filename to check for map existence */
     int   type;                    /* the type of the map */
-    int   fpin;                    /* in  filepointer for program maps */
-    int   fpout;                   /* out filepointer for program maps */
+    int   fpin;                    /* in  file pointer for program maps */
+    int   fpout;                   /* out file pointer for program maps */
+    char *(*func)(request_rec *,   /* function pointer for internal maps */
+                  char *);         
 } rewritemap_entry;
 
 typedef struct {
@@ -385,13 +389,19 @@
 static char *expand_tildepaths(request_rec *r, char *uri);
 static void  expand_map_lookups(request_rec *r, char *uri, int uri_len);
 
-    /* DBM hashfile support functions */
+    /* rewrite map support functions */
 static char *lookup_map(request_rec *r, char *name, char *key);
 static char *lookup_map_txtfile(request_rec *r, char *file, char *key);
 #if HAS_NDBM_LIB
 static char *lookup_map_dbmfile(request_rec *r, char *file, char *key);
 #endif
 static char *lookup_map_program(request_rec *r, int fpin, int fpout, char *key);
+static char *lookup_map_internal(request_rec *r, char *(*func)(request_rec *r, char *key), char *key);
+static char *rewrite_mapfunc_toupper(request_rec *r, char *key);
+static char *rewrite_mapfunc_tolower(request_rec *r, char *key);
+static char *select_random_value_part(request_rec *r, char *value);
+static void  rewrite_rand_init(void);
+static int   rewrite_rand(int l, int h);
 
     /* rewriting logfile support */
 static void  open_rewritelog(server_rec *s, pool *p);