aboutsummaryrefslogtreecommitdiff
path: root/httpd/server_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'httpd/server_http.c')
-rw-r--r--httpd/server_http.c71
1 files changed, 60 insertions, 11 deletions
diff --git a/httpd/server_http.c b/httpd/server_http.c
index 32b9e7d..26d5392 100644
--- a/httpd/server_http.c
+++ b/httpd/server_http.c
@@ -29,14 +29,16 @@
#include <string.h>
#include <unistd.h>
#include <limits.h>
+#include <fnmatch.h>
#include <stdio.h>
#include <time.h>
#include <resolv.h>
#include <event.h>
-#include <fnmatch.h>
+#include <ctype.h>
#include "httpd.h"
#include "http.h"
+#include "patterns.h"
static int server_httpmethod_cmp(const void *, const void *);
static int server_httperror_cmp(const void *, const void *);
@@ -633,6 +635,7 @@ server_reset_http(struct client *clt)
clt->clt_remote_user = NULL;
clt->clt_bev->readcb = server_read_http;
clt->clt_srv_conf = &srv->srv_conf;
+ str_match_free(&clt->clt_srv_match);
}
ssize_t
@@ -873,6 +876,8 @@ server_close_http(struct client *clt)
clt->clt_descresp = NULL;
free(clt->clt_remote_user);
clt->clt_remote_user = NULL;
+
+ str_match_free(&clt->clt_srv_match);
}
char *
@@ -882,11 +887,34 @@ server_expand_http(struct client *clt, const char *val, char *buf,
struct http_descriptor *desc = clt->clt_descreq;
struct server_config *srv_conf = clt->clt_srv_conf;
char ibuf[128], *str, *path;
- int ret;
+ const char *errstr = NULL, *p;
+ size_t size;
+ int n, ret;
if (strlcpy(buf, val, len) >= len)
return (NULL);
+ /* Find previously matched substrings by index */
+ for (p = val; clt->clt_srv_match.sm_nmatch &&
+ (p = strstr(p, "%")) != NULL; p++) {
+ if (!isdigit(*(p + 1)))
+ continue;
+
+ /* Copy number, leading '%' char and add trailing \0 */
+ size = strspn(p + 1, "0123456789") + 2;
+ if (size >= sizeof(ibuf))
+ return (NULL);
+ (void)strlcpy(ibuf, p, size);
+ n = strtonum(ibuf + 1, 0,
+ clt->clt_srv_match.sm_nmatch - 1, &errstr);
+ if (errstr != NULL)
+ return (NULL);
+
+ /* Expand variable with matched value */
+ if (expand_string(buf, len, ibuf,
+ clt->clt_srv_match.sm_match[n]) != 0)
+ return (NULL);
+ }
if (strstr(val, "$DOCUMENT_URI") != NULL) {
if ((path = url_encode(desc->http_path)) == NULL)
return (NULL);
@@ -982,8 +1010,10 @@ server_response(struct httpd *httpd, struct client *clt)
struct server *srv = clt->clt_srv;
struct server_config *srv_conf = &srv->srv_conf;
struct kv *kv, key, *host;
- int portval = -1;
+ struct str_find sm;
+ int portval = -1, ret;
char *hostval;
+ const char *errstr = NULL;
/* Canonicalize the request path */
if (desc->http_path == NULL ||
@@ -1043,9 +1073,17 @@ server_response(struct httpd *httpd, struct client *clt)
hostname);
}
#endif
- if ((srv_conf->flags & SRVFLAG_LOCATION) == 0 &&
- fnmatch(srv_conf->name, hostname,
- FNM_CASEFOLD) == 0 &&
+ if (srv_conf->flags & SRVFLAG_LOCATION)
+ continue;
+ else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) {
+ str_find(hostname, srv_conf->name,
+ &sm, 1, &errstr);
+ ret = errstr == NULL ? 0 : -1;
+ } else {
+ ret = fnmatch(srv_conf->name,
+ hostname, FNM_CASEFOLD);
+ }
+ if (ret == 0 &&
(portval == -1 ||
(portval != -1 && portval == srv_conf->port))) {
/* Replace host configuration */
@@ -1115,6 +1153,8 @@ server_getlocation(struct client *clt, const char *path)
{
struct server *srv = clt->clt_srv;
struct server_config *srv_conf = clt->clt_srv_conf, *location;
+ const char *errstr = NULL;
+ int ret;
/* Now search for the location */
TAILQ_FOREACH(location, &srv->srv_hosts, entry) {
@@ -1125,11 +1165,20 @@ server_getlocation(struct client *clt, const char *path)
}
#endif
if ((location->flags & SRVFLAG_LOCATION) &&
- location->parent_id == srv_conf->parent_id &&
- fnmatch(location->location, path, FNM_CASEFOLD) == 0) {
- /* Replace host configuration */
- clt->clt_srv_conf = srv_conf = location;
- break;
+ location->parent_id == srv_conf->parent_id) {
+ errstr = NULL;
+ if (location->flags & SRVFLAG_LOCATION_MATCH) {
+ ret = str_match(path, location->location,
+ &clt->clt_srv_match, &errstr);
+ } else {
+ ret = fnmatch(location->location,
+ path, FNM_CASEFOLD);
+ }
+ if (ret == 0 && errstr == NULL) {
+ /* Replace host configuration */
+ clt->clt_srv_conf = srv_conf = location;
+ break;
+ }
}
}