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.
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,
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)
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.
*
};
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 *);
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
#undef timeout_pending
#undef timeout_initialized
{
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;
TAILQ_INIT(&http->sockets);
TAILQ_INIT(&http->callbacks);
TAILQ_INIT(&http->connections);
+ TAILQ_INIT(&http->virtualhosts);
return (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 */
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)
{