aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@esdenera.com>2014-09-27 08:50:05 +0200
committerReyk Floeter <reyk@esdenera.com>2014-09-27 08:50:05 +0200
commit2aaf7ee751b511f45418cc4d4a1e21e658a19940 (patch)
treee4e82232c4e100c5eede7799f65e2f3c20acc5c8
parent58771b3259adedefc391e9bb3da319e7502ab66f (diff)
downloadhttpd-2aaf7ee751b511f45418cc4d4a1e21e658a19940.tar.gz
httpd-2aaf7ee751b511f45418cc4d4a1e21e658a19940.zip
sync
-rw-r--r--httpd.h3
-rw-r--r--server_http.c83
2 files changed, 74 insertions, 12 deletions
diff --git a/httpd.h b/httpd.h
index 5c197cf..9ddf3c0 100644
--- a/httpd.h
+++ b/httpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.h,v 1.58 2014/09/05 10:04:20 reyk Exp $ */
+/* $OpenBSD: httpd.h,v 1.59 2014/09/10 15:39:57 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -527,6 +527,7 @@ struct server_config *
server_getlocation(struct client *, const char *);
const char *
server_http_host(struct sockaddr_storage *, char *, size_t);
+char *server_http_parsehost(char *, char *, size_t, int *);
ssize_t server_http_time(time_t, char *, size_t);
int server_log_http(struct client *, u_int, size_t);
diff --git a/server_http.c b/server_http.c
index 6ba5c15..3735131 100644
--- a/server_http.c
+++ b/server_http.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_http.c,v 1.48 2014/09/05 15:06:05 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.50 2014/09/15 08:00:27 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -229,18 +229,20 @@ server_read_http(struct bufferevent *bev, void *arg)
goto fail;
}
desc->http_version = strchr(desc->http_path, ' ');
- if (desc->http_version != NULL)
- *desc->http_version++ = '\0';
+ if (desc->http_version == NULL) {
+ free(line);
+ goto fail;
+ }
+ *desc->http_version++ = '\0';
desc->http_query = strchr(desc->http_path, '?');
if (desc->http_query != NULL)
*desc->http_query++ = '\0';
/*
* Have to allocate the strings because they could
- * be changed independetly by the filters later.
+ * be changed independently by the filters later.
*/
- if (desc->http_version != NULL &&
- (desc->http_version =
+ if ((desc->http_version =
strdup(desc->http_version)) == NULL) {
free(line);
goto fail;
@@ -609,6 +611,55 @@ server_http_host(struct sockaddr_storage *ss, char *buf, size_t len)
return (buf);
}
+char *
+server_http_parsehost(char *host, char *buf, size_t len, int *portval)
+{
+ char *start, *end, *port;
+ const char *errstr = NULL;
+
+ if (strlcpy(buf, host, len) >= len) {
+ log_debug("%s: host name too long", __func__);
+ return (NULL);
+ }
+
+ start = buf;
+ end = port = NULL;
+
+ if (*start == '[' && (end = strchr(start, ']')) != NULL) {
+ /* Address enclosed in [] with port, eg. [2001:db8::1]:80 */
+ start++;
+ *end++ = '\0';
+ if ((port = strchr(end, ':')) == NULL || *port == '\0')
+ port = NULL;
+ else
+ port++;
+ memmove(buf, start, strlen(start) + 1);
+ } else if ((end = strchr(start, ':')) != NULL) {
+ /* Name or address with port, eg. www.example.com:80 */
+ *end++ = '\0';
+ port = end;
+ } else {
+ /* Name or address with default port, eg. www.example.com */
+ port = NULL;
+ }
+
+ if (port != NULL) {
+ /* Save the requested port */
+ *portval = strtonum(port, 0, 0xffff, &errstr);
+ if (errstr != NULL) {
+ log_debug("%s: invalid port: %s", __func__,
+ strerror(errno));
+ return (NULL);
+ }
+ *portval = htons(*portval);
+ } else {
+ /* Port not given, indicate the default port */
+ *portval = -1;
+ }
+
+ return (start);
+}
+
void
server_abort_http(struct client *clt, u_int code, const char *msg)
{
@@ -724,6 +775,8 @@ 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;
+ char *hostval;
/* Canonicalize the request path */
if (desc->http_path == NULL ||
@@ -768,17 +821,25 @@ server_response(struct httpd *httpd, struct client *clt)
* XXX the Host can also appear in the URL path.
*/
if (host != NULL) {
- /* XXX maybe better to turn srv_hosts into a tree */
+ if ((hostval = server_http_parsehost(host->kv_value,
+ hostname, sizeof(hostname), &portval)) == NULL)
+ goto fail;
+
TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
#ifdef DEBUG
if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) {
- DPRINTF("%s: virtual host \"%s\" host \"%s\"",
- __func__, srv_conf->name, host->kv_value);
+ DPRINTF("%s: virtual host \"%s:%u\""
+ " host \"%s\" (\"%s\")",
+ __func__, srv_conf->name,
+ ntohs(srv_conf->port), host->kv_value,
+ hostname);
}
#endif
if ((srv_conf->flags & SRVFLAG_LOCATION) == 0 &&
- fnmatch(srv_conf->name, host->kv_value,
- FNM_CASEFOLD) == 0) {
+ fnmatch(srv_conf->name, hostname,
+ FNM_CASEFOLD) == 0 &&
+ (portval == -1 ||
+ (portval != -1 && portval == srv_conf->port))) {
/* Replace host configuration */
clt->clt_srv_conf = srv_conf;
srv_conf = NULL;