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.c255
1 files changed, 194 insertions, 61 deletions
diff --git a/httpd/server_http.c b/httpd/server_http.c
index 7b65a5e..9a6609e 100644
--- a/httpd/server_http.c
+++ b/httpd/server_http.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_http.c,v 1.79 2015/05/03 18:39:58 florian Exp $ */
+/* $OpenBSD: server_http.c,v 1.89 2015/07/16 19:05:28 reyk Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -29,14 +29,17 @@
#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 <vis.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 +636,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
@@ -738,7 +742,7 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
const char *httperr = NULL, *style;
char *httpmsg, *body = NULL, *extraheader = NULL;
char tmbuf[32], hbuf[128];
- char buf[IBUF_READ_SIZE], *ptr = NULL;
+ char buf[IBUF_READ_SIZE];
int bodylen;
if (code == 0) {
@@ -770,16 +774,13 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
if (msg == NULL)
break;
memset(buf, 0, sizeof(buf));
- if ((ptr = server_expand_http(clt, msg,
- buf, sizeof(buf))) == NULL)
- goto done;
- if ((ptr = url_encode(ptr)) == NULL)
+ if (server_expand_http(clt, msg, buf, sizeof(buf)) == NULL)
goto done;
- if (asprintf(&extraheader, "Location: %s\r\n", ptr) == -1) {
+ if (asprintf(&extraheader, "Location: %s\r\n", buf) == -1) {
code = 500;
extraheader = NULL;
}
- msg = ptr;
+ msg = buf;
break;
case 401:
if (asprintf(&extraheader,
@@ -858,7 +859,6 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
server_close(clt, httpmsg);
free(httpmsg);
}
- free(ptr);
}
void
@@ -877,6 +877,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 *
@@ -885,20 +887,56 @@ 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;
+ char ibuf[128], *str, *path, *query;
+ 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 ((str = url_encode(clt->clt_srv_match.sm_match[n])) == NULL)
+ return (NULL);
+ ret = expand_string(buf, len, ibuf, str);
+ free(str);
+ if (ret != 0)
+ return (NULL);
+ }
if (strstr(val, "$DOCUMENT_URI") != NULL) {
- if (expand_string(buf, len, "$DOCUMENT_URI",
- desc->http_path) != 0)
+ if ((path = url_encode(desc->http_path)) == NULL)
+ return (NULL);
+ ret = expand_string(buf, len, "$DOCUMENT_URI", path);
+ free(path);
+ if (ret != 0)
return (NULL);
}
if (strstr(val, "$QUERY_STRING") != NULL) {
- if (expand_string(buf, len, "$QUERY_STRING",
- desc->http_query == NULL ? "" :
- desc->http_query) != 0)
+ if (desc->http_query == NULL) {
+ ret = expand_string(buf, len, "$QUERY_STRING", "");
+ } else {
+ if ((query = url_encode(desc->http_query)) == NULL)
+ return (NULL);
+ ret = expand_string(buf, len, "$QUERY_STRING", query);
+ free(query);
+ }
+ if (ret != 0)
return (NULL);
}
if (strstr(val, "$REMOTE_") != NULL) {
@@ -919,27 +957,39 @@ server_expand_http(struct client *clt, const char *val, char *buf,
}
if (strstr(val, "$REMOTE_USER") != NULL) {
if ((srv_conf->flags & SRVFLAG_AUTH) &&
- clt->clt_remote_user != NULL)
- str = clt->clt_remote_user;
- else
- str = "";
- if (expand_string(buf, len,
- "$REMOTE_USER", str) != 0)
+ clt->clt_remote_user != NULL) {
+ if ((str = url_encode(clt->clt_remote_user))
+ == NULL)
+ return (NULL);
+ } else
+ str = strdup("");
+ ret = expand_string(buf, len, "$REMOTE_USER", str);
+ free(str);
+ if (ret != 0)
return (NULL);
}
}
if (strstr(val, "$REQUEST_URI") != NULL) {
+ if ((path = url_encode(desc->http_path)) == NULL)
+ return (NULL);
if (desc->http_query == NULL) {
- if ((str = strdup(desc->http_path)) == NULL)
+ str = path;
+ } else {
+ if ((query = url_encode(desc->http_query)) == NULL) {
+ free(path);
+ return (NULL);
+ }
+ ret = asprintf(&str, "%s?%s", path, query);
+ free(path);
+ free(query);
+ if (ret == -1)
return (NULL);
- } else if (asprintf(&str, "%s?%s",
- desc->http_path, desc->http_query) == -1)
- return (NULL);
- if (expand_string(buf, len, "$REQUEST_URI", str) != 0) {
- free(str);
- return (NULL);
}
+
+ ret = expand_string(buf, len, "$REQUEST_URI", str);
free(str);
+ if (ret != 0)
+ return (NULL);
}
if (strstr(val, "$SERVER_") != NULL) {
if (strstr(val, "$SERVER_ADDR") != NULL) {
@@ -958,8 +1008,12 @@ server_expand_http(struct client *clt, const char *val, char *buf,
return (NULL);
}
if (strstr(val, "$SERVER_NAME") != NULL) {
- if (expand_string(buf, len,
- "$SERVER_NAME", srv_conf->name) != 0)
+ if ((str = url_encode(srv_conf->name))
+ == NULL)
+ return (NULL);
+ ret = expand_string(buf, len, "$SERVER_NAME", str);
+ free(str);
+ if (ret != 0)
return (NULL);
}
}
@@ -977,8 +1031,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 ||
@@ -1038,9 +1094,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 */
@@ -1110,6 +1174,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) {
@@ -1120,11 +1186,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;
+ }
}
}
@@ -1133,7 +1208,7 @@ server_getlocation(struct client *clt, const char *path)
int
server_response_http(struct client *clt, u_int code,
- struct media_type *media, size_t size, time_t mtime)
+ struct media_type *media, off_t size, time_t mtime)
{
struct http_descriptor *desc = clt->clt_descreq;
struct http_descriptor *resp = clt->clt_descresp;
@@ -1174,7 +1249,7 @@ server_response_http(struct client *clt, u_int code,
/* Set content length, if specified */
if ((cl =
kv_add(&resp->http_headers, "Content-Length", NULL)) == NULL ||
- kv_set(cl, "%ld", size) == -1)
+ kv_set(cl, "%lld", (long long)size) == -1)
return (-1);
/* Set last modification time */
@@ -1352,6 +1427,13 @@ server_log_http(struct client *clt, u_int code, size_t len)
struct tm *tm;
struct server_config *srv_conf;
struct http_descriptor *desc;
+ int ret = -1;
+ char *user = NULL;
+ char *path = NULL;
+ char *query = NULL;
+ char *version = NULL;
+ char *referrer_v = NULL;
+ char *agent_v = NULL;
if ((srv_conf = clt->clt_srv_conf) == NULL)
return (-1);
@@ -1380,18 +1462,34 @@ server_log_http(struct client *clt, u_int code, size_t len)
*/
switch (srv_conf->logformat) {
case LOG_FORMAT_COMMON:
- if (evbuffer_add_printf(clt->clt_log,
+ /* Use vis to encode input values from the header */
+ if (clt->clt_remote_user &&
+ stravis(&user, clt->clt_remote_user, HTTPD_LOGVIS) == -1)
+ goto done;
+ if (desc->http_version &&
+ stravis(&version, desc->http_version, HTTPD_LOGVIS) == -1)
+ goto done;
+
+ /* The following should be URL-encoded */
+ if (desc->http_path &&
+ (path = url_encode(desc->http_path)) == NULL)
+ goto done;
+ if (desc->http_query &&
+ (query = url_encode(desc->http_query)) == NULL)
+ goto done;
+
+ ret = evbuffer_add_printf(clt->clt_log,
"%s %s - %s [%s] \"%s %s%s%s%s%s\" %03d %zu\n",
srv_conf->name, ip, clt->clt_remote_user == NULL ? "-" :
- clt->clt_remote_user, tstamp,
+ user, tstamp,
server_httpmethod_byid(desc->http_method),
- desc->http_path == NULL ? "" : desc->http_path,
+ desc->http_path == NULL ? "" : path,
desc->http_query == NULL ? "" : "?",
- desc->http_query == NULL ? "" : desc->http_query,
+ desc->http_query == NULL ? "" : query,
desc->http_version == NULL ? "" : " ",
- desc->http_version == NULL ? "" : desc->http_version,
- code, len) == -1)
- return (-1);
+ desc->http_version == NULL ? "" : version,
+ code, len);
+
break;
case LOG_FORMAT_COMBINED:
@@ -1405,29 +1503,64 @@ server_log_http(struct client *clt, u_int code, size_t len)
agent->kv_value == NULL)
agent = NULL;
- if (evbuffer_add_printf(clt->clt_log,
+ /* Use vis to encode input values from the header */
+ if (clt->clt_remote_user &&
+ stravis(&user, clt->clt_remote_user, HTTPD_LOGVIS) == -1)
+ goto done;
+ if (desc->http_version &&
+ stravis(&version, desc->http_version, HTTPD_LOGVIS) == -1)
+ goto done;
+ if (agent &&
+ stravis(&agent_v, agent->kv_value, HTTPD_LOGVIS) == -1)
+ goto done;
+
+ /* The following should be URL-encoded */
+ if (desc->http_path &&
+ (path = url_encode(desc->http_path)) == NULL)
+ goto done;
+ if (desc->http_query &&
+ (query = url_encode(desc->http_query)) == NULL)
+ goto done;
+ if (referrer &&
+ (referrer_v = url_encode(referrer->kv_value)) == NULL)
+ goto done;
+
+ ret = evbuffer_add_printf(clt->clt_log,
"%s %s - %s [%s] \"%s %s%s%s%s%s\""
" %03d %zu \"%s\" \"%s\"\n",
srv_conf->name, ip, clt->clt_remote_user == NULL ? "-" :
- clt->clt_remote_user, tstamp,
+ user, tstamp,
server_httpmethod_byid(desc->http_method),
- desc->http_path == NULL ? "" : desc->http_path,
+ desc->http_path == NULL ? "" : path,
desc->http_query == NULL ? "" : "?",
- desc->http_query == NULL ? "" : desc->http_query,
+ desc->http_query == NULL ? "" : query,
desc->http_version == NULL ? "" : " ",
- desc->http_version == NULL ? "" : desc->http_version,
+ desc->http_version == NULL ? "" : version,
code, len,
- referrer == NULL ? "" : referrer->kv_value,
- agent == NULL ? "" : agent->kv_value) == -1)
- return (-1);
+ referrer == NULL ? "" : referrer_v,
+ agent == NULL ? "" : agent_v);
+
break;
case LOG_FORMAT_CONNECTION:
- if (evbuffer_add_printf(clt->clt_log, " [%s]",
- desc->http_path == NULL ? "" : desc->http_path) == -1)
- return (-1);
+ /* URL-encode the path */
+ if (desc->http_path &&
+ (path = url_encode(desc->http_path)) == NULL)
+ goto done;
+
+ ret = evbuffer_add_printf(clt->clt_log, " [%s]",
+ desc->http_path == NULL ? "" : path);
+
break;
}
- return (0);
+done:
+ free(user);
+ free(path);
+ free(query);
+ free(version);
+ free(referrer_v);
+ free(agent_v);
+
+ return (ret);
}