Hello,

I know, it considered featuritis, but still, hey, it should go somewhere.
This diff is based on the diff sent here by Stanislav Adaszewski (s.adaszev...@gmail.com),
some time ago.
I've added one option 'test', i.e.: pass rewrite [test] index.php?q=%1, so it will not rewrite if file or directory present, and a manual page section, describing the rule.
For those like me, trying to stick with base as much as possible.

suggestions?


diff --git a/httpd.conf b/httpd.conf
new file mode 100644
index 0000000..bbef08f
--- /dev/null
+++ b/httpd.conf
@@ -0,0 +1,35 @@
+# $OpenBSD: httpd.conf,v 1.14 2015/02/04 08:39:35 florian Exp $
+
+#
+# Macros
+#
+
+
+#
+# Global Options
+#
+# prefork 3
+
+types {
+    include "/usr/share/misc/mime.types"
+}
+
+#
+# Servers
+#
+
+# A minimal default server
+server "default" {
+    listen on * port 80
+
+
+    location "*.php" {
+        fastcgi socket "/run/php-fpm.sock"
+    }
+    location match "(%w+)" {
+        pass rewrite "/test.php?q=%1"
+#        fastcgi socket "/run/php-fpm.sock"
+    }
+
+
+}
diff --git a/httpd.conf.5 b/httpd.conf.5
index 193fa53..ccb1890 100644
--- a/httpd.conf.5
+++ b/httpd.conf.5
@@ -388,6 +388,8 @@ The pattern may contain captures that can be used in the
 .Ar uri
 of an enclosed
 .Ic block return
+or
+.Ic pass rewrite
 option.
 .It Oo Ic no Oc Ic log Op Ar option
 Set the specified logging options.
@@ -446,6 +448,16 @@ instead of the log files.
 Disable any previous
 .Ic block
 in a location.
+.It Ic pass rewrite Oo Ic test Oc Ic Ar uri
+Disable any previous block in location, the path gets rewritten as specified in
+.Ic block return
+statement. If
+.Ic test
+option is present, the rewrite will
+.Em not
+happen if file or directory referenced by the
+.Ar uri
+present.
 .It Ic root Ar option
 Configure the document root and options for the request path.
 Valid options are:
diff --git a/httpd.h b/httpd.h
index d0892b6..5419835 100644
--- a/httpd.h
+++ b/httpd.h
@@ -41,7 +41,6 @@
 #ifndef nitems
 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
 #endif
-
 #define CONF_FILE        "/etc/httpd.conf"
 #define HTTPD_SOCKET        "/var/run/httpd.sock"
 #define HTTPD_USER        "www"
@@ -73,6 +72,7 @@
 #define SERVER_MAX_PREFETCH    256
 #define SERVER_MIN_PREFETCHED    32
 #define SERVER_HSTS_DEFAULT_AGE    31536000
+#define SERVER_MAX_RECUR_REWR    0

 #define MEDIATYPE_NAMEMAX    128    /* file name extension */
 #define MEDIATYPE_TYPEMAX    64    /* length of type/subtype */
@@ -364,13 +364,15 @@ SPLAY_HEAD(client_tree, client);
 #define SRVFLAG_SERVER_MATCH    0x00200000
 #define SRVFLAG_SERVER_HSTS    0x00400000
 #define SRVFLAG_DEFAULT_TYPE    0x00800000
+#define SRVFLAG_REWRITE        0x01000000
+#define    SRVFLAG_TEST        0x02000000

 #define SRVFLAG_BITS                            \
     "\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX" \
"\05ROOT\06LOCATION\07FCGI\10NO_FCGI\11LOG\12NO_LOG\13SOCKET"    \
     "\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG" \
     "\21AUTH\22NO_AUTH\23BLOCK\24NO_BLOCK\25LOCATION_MATCH"     \
-    "\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE"
+ "\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE\31REWRITE\32TEST"

 #define TCPFLAG_NODELAY        0x01
 #define TCPFLAG_NNODELAY    0x02
@@ -472,6 +474,7 @@ struct server_config {
     int             return_code;
     char            *return_uri;
     off_t             return_uri_len;
+    char            rewrite_uri[PATH_MAX];

     int             hsts_max_age;
     uint8_t             hsts_flags;
diff --git a/parse.y b/parse.y
index ec885cc..8c9aafe 100644
--- a/parse.y
+++ b/parse.y
@@ -134,7 +134,7 @@ typedef struct {
%token LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY OCSP ON PORT PREFORK %token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TIMEOUT
 %token    TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
-%token    ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS
+%token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE TEST
 %token    <v.string>    STRING
 %token  <v.number>    NUMBER
 %type    <v.port>    port
@@ -971,6 +971,29 @@ filter        : block RETURN NUMBER optstring    {
             /* Forbidden */
             srv_conf->return_code = 403;
         }
+        | PASS REWRITE STRING        {
+            srv_conf->flags |= SRVFLAG_REWRITE;
+            if (strlcpy(srv_conf->rewrite_uri, $3,
+                sizeof(srv_conf->rewrite_uri)) >=
+                sizeof(srv_conf->rewrite_uri)) {
+                yyerror("url rewrite string too long");
+                free($3);
+                YYERROR;
+            }
+            free($3);
+        }
+        | PASS REWRITE TEST STRING    {
+            srv_conf->flags |= SRVFLAG_REWRITE;
+            srv_conf->flags |= SRVFLAG_TEST;
+            if (strlcpy(srv_conf->rewrite_uri, $4,
+                sizeof(srv_conf->rewrite_uri)) >=
+                sizeof(srv_conf->rewrite_uri)) {
+                yyerror("url rewrite string too long");
+                free($4);
+                YYERROR;
+            }
+            free($4);
+        }
         | PASS                {
             srv_conf->flags &= ~SRVFLAG_BLOCK;
             srv_conf->flags |= SRVFLAG_NO_BLOCK;
@@ -1231,6 +1254,7 @@ lookup(char *s)
         { "request",        REQUEST },
         { "requests",        REQUESTS },
         { "return",        RETURN },
+        { "rewrite",         REWRITE },
         { "root",        ROOT },
         { "sack",        SACK },
         { "server",        SERVER },
@@ -1240,6 +1264,7 @@ lookup(char *s)
         { "subdomains",        SUBDOMAINS },
         { "syslog",        SYSLOG },
         { "tcp",        TCP },
+        { "test",        TEST },
         { "timeout",        TIMEOUT },
         { "tls",        TLS },
         { "type",        TYPE },
diff --git a/server_http.c b/server_http.c
index 968d51a..2b992d3 100644
--- a/server_http.c
+++ b/server_http.c
@@ -20,6 +20,7 @@
 #include <sys/queue.h>
 #include <sys/socket.h>
 #include <sys/tree.h>
+#include <sys/stat.h>

 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -1039,7 +1040,7 @@ server_expand_http(struct client *clt, const char *val, char *buf,
 int
 server_response(struct httpd *httpd, struct client *clt)
 {
-    char             path[PATH_MAX];
+    char             path[PATH_MAX],d_path[PATH_MAX];
     char             hostname[HOST_NAME_MAX+1];
     struct http_descriptor    *desc = clt->clt_descreq;
     struct http_descriptor    *resp = clt->clt_descresp;
@@ -1047,9 +1048,12 @@ server_response(struct httpd *httpd, struct client *clt)
     struct server_config    *srv_conf = &srv->srv_conf;
     struct kv        *kv, key, *host;
     struct str_find         sm;
+    struct stat         st;
     int             portval = -1, ret;
     char            *hostval;
     const char        *errstr = NULL;
+    char            buf[IBUF_READ_SIZE];
+    int n;

     /* Canonicalize the request path */
     if (desc->http_path == NULL ||
@@ -1154,6 +1158,76 @@ server_response(struct httpd *httpd, struct client *clt)
     /* Now search for the location */
     srv_conf = server_getlocation(clt, desc->http_path);

+
+    /* URL Rewriting logic */
+    DPRINTF("%s: URL Rewriting logic, flags: %08X, rewrite_uri: %s, "
+            "http_path: %s\n", __func__, srv_conf->flags,
+            srv_conf->rewrite_uri, desc->http_path);
+    for (n = 0; srv_conf->flags & SRVFLAG_REWRITE; n++) {
+        if (n > SERVER_MAX_RECUR_REWR) {
+            server_abort_http(clt, 500, "recursive "
+                    "rewrite limit exceeded");
+            return (-1);
+        }
+        if (srv_conf->flags & SRVFLAG_TEST) {
+ snprintf(d_path,PATH_MAX,"%s%s",srv_conf->root,path);
+            if (stat(d_path,&st)) {
+ DPRINTF("%s: Rewrite test from: %s to %s, n: %d\n", __func__,
+                        desc->http_path, srv_conf->rewrite_uri, n);
+                if (server_expand_http(clt, srv_conf->rewrite_uri, buf,
+                            sizeof(buf)) == NULL) {
+                    server_abort_http(clt, 500, strerror(errno));
+                    return (-1);
+                }
+                if (desc->http_path != NULL) {
+                    free(desc->http_path);
+                    desc->http_path = NULL;
+                }
+                desc->http_path = strdup(buf);
+                if (desc->http_path == NULL) {
+                    server_abort_http(clt, 500, strerror(errno));
+                    return (-1);
+                }
+                desc->http_query = strchr(desc->http_path, '?');
+                if (desc->http_query != NULL) {
+                    *desc->http_query++ = '\0';
+                    desc->http_query = strdup(desc->http_query);
+                    if (desc->http_query == NULL) {
+                        server_abort_http(clt, 500, strerror(errno));
+                    }
+                }
+                srv_conf = server_getlocation(clt, desc->http_path);
+            }
+            else break;
+         } else {
+            DPRINTF("%s: Rewrite from: %s to %s, n: %d\n", __func__,
+                    desc->http_path, srv_conf->rewrite_uri, n);
+            if (server_expand_http(clt, srv_conf->rewrite_uri, buf,
+                        sizeof(buf)) == NULL) {
+                server_abort_http(clt, 500, strerror(errno));
+                return (-1);
+            }
+            if (desc->http_path != NULL) {
+                free(desc->http_path);
+                desc->http_path = NULL;
+            }
+            desc->http_path = strdup(buf);
+            if (desc->http_path == NULL) {
+                server_abort_http(clt, 500, strerror(errno));
+                return (-1);
+            }
+            desc->http_query = strchr(desc->http_path, '?');
+            if (desc->http_query != NULL) {
+                *desc->http_query++ = '\0';
+                desc->http_query = strdup(desc->http_query);
+                if (desc->http_query == NULL) {
+                    server_abort_http(clt, 500, strerror(errno));
+                }
+            }
+            srv_conf = server_getlocation(clt, desc->http_path);
+        }
+    }
+
     if (srv_conf->flags & SRVFLAG_BLOCK) {
         server_abort_http(clt, srv_conf->return_code,
             srv_conf->return_uri);
@@ -1196,8 +1270,10 @@ server_getlocation(struct client *clt, const char *path)
     TAILQ_FOREACH(location, &srv->srv_hosts, entry) {
 #ifdef DEBUG
         if (location->flags & SRVFLAG_LOCATION) {
-            DPRINTF("%s: location \"%s\" path \"%s\"",
-                __func__, location->location, path);
+            DPRINTF("%s: location \"%s\" path \"%s\" flags: %08X "
+                "rewrite_uri: %s",
+                __func__, location->location, path, location->flags,
+                location->rewrite_uri);
         }
 #endif
         if ((location->flags & SRVFLAG_LOCATION) &&

Reply via email to