]> granicus.if.org Git - libevent/commitdiff
add support for virtual http hosts; no tests yet
authorNiels Provos <provos@gmail.com>
Mon, 5 May 2008 07:17:05 +0000 (07:17 +0000)
committerNiels Provos <provos@gmail.com>
Mon, 5 May 2008 07:17:05 +0000 (07:17 +0000)
svn:r771

ChangeLog
configure.in
evhttp.h
http-internal.h
http.c

index d5d7231f3dc0fb7bb337bbb1be8fa356fae89e68..de35c9b1890460852edc5285f8f37a0f15a84108 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
index 70a8e1afb2d8df501afd96b230f1ea968722804c..cab67a0acf111a60714e91abd4a49a084fd376a9 100644 (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)
 
index 6f53d2e46e80d9b84c05f3e062df541a7fb52d97..eba72721d0192800f185dcc80db0cdc723c49f55 100644 (file)
--- a/evhttp.h
+++ b/evhttp.h
@@ -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.
  *
index c5bd5ddfec393c9350419a5aca1431efc0de29d5..272a2a1c81322b4446ae74163b038d8ee3a2d2f4 100644 (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 *);
diff --git a/http.c b/http.c
index 9f0c4f013efe31bf1d91726c51ec0f6bca911a66..217a6dc530003d1da5705f560cd11cbca54dc33d 100644 (file)
--- a/http.c
+++ b/http.c
@@ -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)
 {