add support for virtual http hosts; no tests yet

svn:r771
This commit is contained in:
Niels Provos 2008-05-05 07:17:05 +00:00
parent f940eb4b8d
commit f2a81fbc67
5 changed files with 105 additions and 2 deletions

View File

@ -88,6 +88,7 @@ Changes in current version:
o reduce system calls for getting current time by caching it.
o separate signal events from io events; making the code less complex.
o support for periodic timeouts
o support for virtual HTTP hosts.
Changes in 1.4.0:
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.

View File

@ -53,7 +53,7 @@ AM_CONDITIONAL(ZLIB_REGRESS, [test "$have_zlib" != "no"])
dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in6.h sys/socket.h sys/uio.h)
AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in6.h sys/socket.h sys/uio.h fnmatch.h)
if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
AC_EGREP_CPP(yes,
@ -146,7 +146,7 @@ AC_C_INLINE
AC_HEADER_TIME
dnl Checks for library functions.
AC_CHECK_FUNCS(gettimeofday vasprintf fcntl clock_gettime strtok_r strsep getaddrinfo getnameinfo strlcpy inet_ntop signal sigaction strtoll)
AC_CHECK_FUNCS(gettimeofday vasprintf fcntl clock_gettime strtok_r strsep getaddrinfo getnameinfo strlcpy inet_ntop signal sigaction strtoll fnmatch)
AC_CHECK_SIZEOF(long)

View File

@ -138,6 +138,41 @@ int evhttp_del_cb(struct evhttp *, const char *);
void evhttp_set_gencb(struct evhttp *http,
void (*cb)(struct evhttp_request *, void *), void *arg);
/**
Adds a virtual host to the http server.
A virtual host is a newly initialized evhttp object that has request
callbacks set on it via evhttp_set_cb() or evhttp_set_gencb(). It
most not have any listing sockets associated with it.
If the virtual host has not been removed by the time that evhttp_free()
is called on the main http server, it will be automatically freed, too.
It is possible to have hierarchical vhosts. For example: A vhost
with the pattern *.example.com may have other vhosts with patterns
foo.example.com and bar.example.com associated with it.
@param http the evhttp object to which to add a virtual host
@param pattern the glob pattern against which the hostname is matched.
The match is case insensitive and follows otherwise regular shell
matching.
@param vhost the virtual host to add the regular http server.
@return 0 on success, -1 on failure
@see evhttp_remove_virtual_host()
*/
int evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
struct evhttp* vhost);
/**
Removes a virtual host from the http server.
@param http the evhttp object from which to remove the virtual host
@param vhost the virtual host to remove from the regular http server.
@return 0 on success, -1 on failure
@see evhttp_add_virtual_host()
*/
int evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost);
/**
* Set the timeout for an HTTP request.
*

View File

@ -99,11 +99,18 @@ struct evhttp_bound_socket {
};
struct evhttp {
TAILQ_ENTRY(evhttp) next;
TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
struct evconq connections;
TAILQ_HEAD(vhostsq, evhttp) virtualhosts;
/* NULL if this server is not a vhost */
char *vhost_pattern;
int timeout;
void (*gencb)(struct evhttp_request *req, void *);

60
http.c
View File

@ -79,6 +79,9 @@
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_FNMATCH_H
#include <fnmatch.h>
#endif
#undef timeout_pending
#undef timeout_initialized
@ -1891,12 +1894,26 @@ evhttp_handle_request(struct evhttp_request *req, void *arg)
{
struct evhttp *http = arg;
struct evhttp_cb *cb = NULL;
const char *hostname;
if (req->uri == NULL) {
evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
return;
}
/* handle potential virtual hosts */
hostname = evhttp_find_header(req->input_headers, "Host");
if (hostname != NULL) {
struct evhttp *vhost;
TAILQ_FOREACH(vhost, &http->virtualhosts, next) {
if (fnmatch(vhost->vhost_pattern, hostname,
FNM_CASEFOLD) == 0) {
evhttp_handle_request(req, vhost);
return;
}
}
}
if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
(*cb->cb)(req, cb->cbarg);
return;
@ -2017,6 +2034,7 @@ evhttp_new_object(void)
TAILQ_INIT(&http->sockets);
TAILQ_INIT(&http->callbacks);
TAILQ_INIT(&http->connections);
TAILQ_INIT(&http->virtualhosts);
return (http);
}
@ -2054,6 +2072,7 @@ evhttp_free(struct evhttp* http)
struct evhttp_cb *http_cb;
struct evhttp_connection *evcon;
struct evhttp_bound_socket *bound;
struct evhttp* vhost;
evutil_socket_t fd;
/* Remove the accepting part */
@ -2077,10 +2096,51 @@ evhttp_free(struct evhttp* http)
mm_free(http_cb->what);
mm_free(http_cb);
}
while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) {
TAILQ_REMOVE(&http->virtualhosts, vhost, next);
evhttp_free(vhost);
}
if (http->vhost_pattern != NULL)
mm_free(http->vhost_pattern);
mm_free(http);
}
int
evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
struct evhttp* vhost)
{
/* a vhost can only be a vhost once and should not have bound sockets */
if (vhost->vhost_pattern != NULL ||
TAILQ_FIRST(&vhost->sockets) != NULL)
return (-1);
vhost->vhost_pattern = mm_strdup(pattern);
if (vhost->vhost_pattern == NULL)
return (-1);
TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next);
return (0);
}
int
evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost)
{
if (vhost->vhost_pattern == NULL)
return (-1);
TAILQ_REMOVE(&http->virtualhosts, vhost, next);
mm_free(vhost->vhost_pattern);
vhost->vhost_pattern = NULL;
return (0);
}
void
evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
{