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) &&