uhttpd: move Lua and TLS support into loadable plugins
authorJo-Philipp Wich <jow@openwrt.org>
Thu, 25 Mar 2010 02:04:50 +0000 (02:04 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Thu, 25 Mar 2010 02:04:50 +0000 (02:04 +0000)
contrib/package/uhttpd/Makefile
contrib/package/uhttpd/src/Makefile
contrib/package/uhttpd/src/uhttpd-lua.c
contrib/package/uhttpd/src/uhttpd-lua.h
contrib/package/uhttpd/src/uhttpd-tls.c
contrib/package/uhttpd/src/uhttpd-tls.h
contrib/package/uhttpd/src/uhttpd-utils.c
contrib/package/uhttpd/src/uhttpd.c
contrib/package/uhttpd/src/uhttpd.h

index 802fb209e66b58a3610b4428a26109dcc7ca91a4..c7e18c9ba08d9bd90f9c927831d71a3702131e2c 100644 (file)
@@ -14,11 +14,15 @@ PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 
 include $(INCLUDE_DIR)/package.mk
 
-define Package/uhttpd
+define Package/uhttpd/default
   SECTION:=net
   CATEGORY:=Network
   TITLE:=uHTTPd - tiny, single threaded HTTP server
-  DEPENDS:=+liblua +libcyassl +zlib
+endef
+
+define Package/uhttpd
+  $(Package/uhttpd/default)
+  MENU:=1
 endef
 
 define Package/uhttpd/description
@@ -27,6 +31,29 @@ define Package/uhttpd/description
  HTTP daemon.
 endef
 
+
+define Package/uhttpd-mod-tls
+  $(Package/uhttpd/default)
+  TITLE+= (TLS plugin)
+  DEPENDS:=uhttpd +libcyassl
+endef
+
+define Package/uhttpd-mod-tls/description
+ The TLS plugin adds HTTPS support to uHTTPd.
+endef
+
+
+define Package/uhttpd-mod-lua
+  $(Package/uhttpd/default)
+  TITLE+= (Lua plugin)
+  DEPENDS:=uhttpd +liblua
+endef
+
+define Package/uhttpd-mod-lua/description
+ The Lua plugin adds a CGI-like Lua runtime interface to uHTTPd.
+endef
+
+
 # hack to use CyASSL headers
 TARGET_CFLAGS += -I$(firstword $(wildcard $(BUILD_DIR)/cyassl-*/include))
 
@@ -48,4 +75,17 @@ define Package/uhttpd/install
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd $(1)/usr/sbin/uhttpd
 endef
 
+define Package/uhttpd-mod-tls/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd_tls.so $(1)/usr/lib/
+endef
+
+define Package/uhttpd-mod-lua/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd_lua.so $(1)/usr/lib/
+endef
+
+
 $(eval $(call BuildPackage,uhttpd))
+$(eval $(call BuildPackage,uhttpd-mod-tls))
+$(eval $(call BuildPackage,uhttpd-mod-lua))
index 7bbb23afc1e76503096133c634907ba389d73890..06d61bdef3b3e7b9d64aa2edb764c8d815ffa247 100644 (file)
@@ -3,36 +3,50 @@ LUA_SUPPORT ?= 1
 TLS_SUPPORT ?= 1
 
 CFLAGS ?= -I./lua-5.1.4/src -I./cyassl-1.4.0/include -O0 -ggdb3
-LDFLAGS ?= -L./lua-5.1.4/src -L./cyassl-1.4.0/src/.libs -lm
+LDFLAGS ?= -L./lua-5.1.4/src -L./cyassl-1.4.0/src/.libs
 
 CFLAGS += -Wall --std=gnu99
-LDFLAGS += -lm -lcrypt
 
 OBJ = uhttpd.o uhttpd-file.o uhttpd-utils.o
+LIB = -Wl,--export-dynamic -lcrypt -ldl
+
+TLSLIB =
+LUALIB =
+
+
+world: compile
 
 ifeq ($(CGI_SUPPORT),1)
-       OBJ += uhttpd-cgi.o
-       CFLAGS += -DHAVE_CGI
+  OBJ += uhttpd-cgi.o
+  CFLAGS += -DHAVE_CGI
 endif
 
 ifeq ($(LUA_SUPPORT),1)
-       OBJ += uhttpd-lua.o
-       CFLAGS += -DHAVE_LUA
-       LDFLAGS += -ldl -llua
+  CFLAGS += -DHAVE_LUA
+  LUALIB = uhttpd_lua.so
+
+  $(LUALIB): uhttpd-lua.c
+               $(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
+                       -shared -lm -llua -ldl \
+                       -o $(LUALIB) uhttpd-lua.c
 endif
 
 ifeq ($(TLS_SUPPORT),1)
-       OBJ += uhttpd-tls.o
-       CFLAGS += -DHAVE_TLS
-       LDFLAGS += -lpthread -lz -lcyassl
+  CFLAGS += -DHAVE_TLS
+  TLSLIB = uhttpd_tls.so
+
+  $(TLSLIB): uhttpd-tls.c
+               $(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
+                       -shared -lcyassl \
+                       -o $(TLSLIB) uhttpd-tls.c
 endif
 
 %.o: %.c
-       $(CC) $(CFLAGS) -c -o $@ $< 
+       $(CC) $(CFLAGS) -c -o $@ $<
 
-compile: $(OBJ)
-       $(CC) -o uhttpd $(LDFLAGS) $(OBJ)
+compile: $(OBJ) $(TLSLIB) $(LUALIB)
+       $(CC) -o uhttpd $(LDFLAGS) $(LIB) $(OBJ)
 
 clean:
-       rm -f *.o uhttpd
+       rm -f *.o *.so uhttpd
 
index db14eda450114bcac82377931c066bfd45f66aa5..ab09841cd62ea39874f0811d03e8f1c90af8a8c1 100644 (file)
@@ -533,3 +533,9 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
        }
 }
 
+void uh_lua_close(lua_State *L)
+{
+       lua_close(L);
+}
+
+
index 518c2bc83a41d7922ac33fe9775c7853a479eeb2..7304665000f11026f59ca9a2c40882fa2d969a61 100644 (file)
@@ -38,4 +38,6 @@ void uh_lua_request(
        struct client *cl, struct http_request *req, lua_State *L
 );
 
+void uh_lua_close(lua_State *L);
+
 #endif
index bbec7509df12ed995a7ea2f7411660286968965c..cb5061638078c75e919371bb45b5efd3118e8976 100644 (file)
@@ -33,6 +33,16 @@ SSL_CTX * uh_tls_ctx_init()
        return c;
 }
 
+int uh_tls_ctx_cert(SSL_CTX *c, const char *file)
+{
+       return SSL_CTX_use_certificate_file(c, file, SSL_FILETYPE_ASN1);
+}
+
+int uh_tls_ctx_key(SSL_CTX *c, const char *file)
+{
+       return SSL_CTX_use_PrivateKey_file(c, file, SSL_FILETYPE_ASN1);
+}
+
 void uh_tls_ctx_free(struct listener *l)
 {
        SSL_CTX_free(l->tls);
@@ -48,6 +58,16 @@ void uh_tls_client_accept(struct client *c)
        }
 }
 
+int uh_tls_client_recv(struct client *c, void *buf, int len)
+{
+       return SSL_read(c->tls, buf, len);
+}
+
+int uh_tls_client_send(struct client *c, void *buf, int len)
+{
+       return SSL_write(c->tls, buf, len);
+}
+
 void uh_tls_client_close(struct client *c)
 {
        if( c->tls )
@@ -58,3 +78,5 @@ void uh_tls_client_close(struct client *c)
                c->tls = NULL;
        }
 }
+
+
index 2de2d26d81816ab3640eefb751cf14a9d875ad56..4a98b78c69c079350d448086507b656b1d35ae0d 100644 (file)
 
 
 SSL_CTX * uh_tls_ctx_init();
-
+int uh_tls_ctx_cert(SSL_CTX *c, const char *file);
+int uh_tls_ctx_key(SSL_CTX *c, const char *file);
 void uh_tls_ctx_free(struct listener *l);
+
 void uh_tls_client_accept(struct client *c);
+int uh_tls_client_recv(struct client *c, void *buf, int len);
+int uh_tls_client_send(struct client *c, void *buf, int len);
 void uh_tls_client_close(struct client *c);
 
 #endif
index 01cfa121b4d46a631404ce5b6b6c342c9575ed46..c1e08b069586b2ee5484d05a97b61cde4c4da325 100644 (file)
@@ -104,7 +104,7 @@ int uh_tcp_send(struct client *cl, const char *buf, int len)
        {
 #ifdef HAVE_TLS
                if( cl->tls )
-                       return SSL_write(cl->tls, buf, len);
+                       return cl->server->conf->tls_send(cl, (void *)buf, len);
                else
 #endif
                        return send(cl->socket, buf, len, 0);
@@ -147,7 +147,7 @@ int uh_tcp_recv(struct client *cl, char *buf, int len)
        {
 #ifdef HAVE_TLS
                if( cl->tls )
-                       rsz = SSL_read(cl->tls, (void *)&buf[sz], len);
+                       rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
                else
 #endif
                        rsz = recv(cl->socket, (void *)&buf[sz], len, 0);
index 401749faee05945e0212d3ff4e45e2dbe3600ce8..a7db794a5bcf64b3a8e9a7c18731eaa86dc0ea5e 100644 (file)
@@ -417,6 +417,10 @@ int main (int argc, char **argv)
        char bind[128];
        char *port = NULL;
 
+       /* library handles */
+       void *tls_lib;
+       void *lua_lib;
+
        /* clear the master and temp sets */
        FD_ZERO(&used_fds);
        FD_ZERO(&serv_fds);
@@ -445,11 +449,39 @@ int main (int argc, char **argv)
        memset(bind, 0, sizeof(bind));
 
 #ifdef HAVE_TLS
-       /* init SSL context */
-       if( ! (conf.tls = uh_tls_ctx_init()) )
+       /* load TLS plugin */
+       if( ! (tls_lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)) )
        {
-               fprintf(stderr, "Failed to initalize SSL context\n");
-               exit(1);
+               fprintf(stderr,
+                       "Notice: Unable to load TLS plugin - disabling SSL support! "
+                       "(Reason: %s)\n", dlerror()
+               );
+       }
+       else
+       {
+               /* resolve functions */
+               if( !(conf.tls_init   = dlsym(tls_lib, "uh_tls_ctx_init"))      ||
+                   !(conf.tls_cert   = dlsym(tls_lib, "uh_tls_ctx_cert"))      ||
+                   !(conf.tls_key    = dlsym(tls_lib, "uh_tls_ctx_key"))       ||
+                   !(conf.tls_free   = dlsym(tls_lib, "uh_tls_ctx_free"))      ||
+                       !(conf.tls_accept = dlsym(tls_lib, "uh_tls_client_accept")) ||
+                       !(conf.tls_close  = dlsym(tls_lib, "uh_tls_client_close"))  ||
+                       !(conf.tls_recv   = dlsym(tls_lib, "uh_tls_client_recv"))   ||
+                       !(conf.tls_send   = dlsym(tls_lib, "uh_tls_client_send"))
+               ) {
+                       fprintf(stderr,
+                               "Error: Failed to lookup required symbols "
+                               "in TLS plugin: %s\n", dlerror()
+                       );
+                       exit(1);
+               }
+
+               /* init SSL context */
+               if( ! (conf.tls = conf.tls_init()) )
+               {
+                       fprintf(stderr, "Error: Failed to initalize SSL context\n");
+                       exit(1);
+               }
        }
 #endif
 
@@ -477,12 +509,23 @@ int main (int argc, char **argv)
                                }
 
                                if( opt == 's' )
+                               {
+                                       if( !conf.tls )
+                                       {
+                                               fprintf(stderr,
+                                                       "Notice: TLS support is disabled, "
+                                                       "ignoring '-s %s'\n", optarg
+                                               );
+                                               continue;
+                                       }
+
                                        tls = 1;
+                               }
 
                                /* bind sockets */
                                bound += uh_socket_bind(
                                        &serv_fds, &max_fd, bind[0] ? bind : NULL, port,
-                                       &hints, tls, &conf
+                                       &hints, (opt == 's'), &conf
                                );
 
                                break;
@@ -490,24 +533,34 @@ int main (int argc, char **argv)
 #ifdef HAVE_TLS
                        /* certificate */
                        case 'C':
-                               if( SSL_CTX_use_certificate_file(conf.tls, optarg, SSL_FILETYPE_ASN1) < 1 )
+                               if( conf.tls )
                                {
-                                       fprintf(stderr, "Invalid certificate file given\n");
-                                       exit(1);
+                                       if( conf.tls_cert(conf.tls, optarg) < 1 )
+                                       {
+                                               fprintf(stderr,
+                                                       "Error: Invalid certificate file given\n");
+                                               exit(1);
+                                       }
+
+                                       keys++;
                                }
 
-                               keys++;
                                break;
 
                        /* key */
                        case 'K':
-                               if( SSL_CTX_use_PrivateKey_file(conf.tls, optarg, SSL_FILETYPE_ASN1) < 1 )
+                               if( conf.tls )
                                {
-                                       fprintf(stderr, "Invalid private key file given\n");
-                                       exit(1);
+                                       if( conf.tls_key(conf.tls, optarg) < 1 )
+                                       {
+                                               fprintf(stderr,
+                                                       "Error: Invalid private key file given\n");
+                                               exit(1);
+                                       }
+
+                                       keys++;
                                }
 
-                               keys++;
                                break;
 #endif
 
@@ -515,7 +568,8 @@ int main (int argc, char **argv)
                        case 'h':
                                if( ! realpath(optarg, conf.docroot) )
                                {
-                                       fprintf(stderr, "Invalid directory %s: %s\n", optarg, strerror(errno));
+                                       fprintf(stderr, "Error: Invalid directory %s: %s\n",
+                                               optarg, strerror(errno));
                                        exit(1);
                                }
                                break;
@@ -604,21 +658,21 @@ int main (int argc, char **argv)
 #ifdef HAVE_TLS
        if( (tls == 1) && (keys < 2) )
        {
-               fprintf(stderr, "Missing private key or certificate file\n");
+               fprintf(stderr, "Error: Missing private key or certificate file\n");
                exit(1);
        }
 #endif
 
        if( bound < 1 )
        {
-               fprintf(stderr, "No sockets bound, unable to continue\n");
+               fprintf(stderr, "Error: No sockets bound, unable to continue\n");
                exit(1);
        }
 
        /* default docroot */
        if( !conf.docroot[0] && !realpath(".", conf.docroot) )
        {
-               fprintf(stderr, "Can not determine default document root: %s\n",
+               fprintf(stderr, "Error: Can not determine default document root: %s\n",
                        strerror(errno));
                exit(1);
        }
@@ -637,14 +691,37 @@ int main (int argc, char **argv)
 #endif
 
 #ifdef HAVE_LUA
-       /* init Lua runtime if handler is specified */
-       if( conf.lua_handler )
+       /* load Lua plugin */
+       if( ! (lua_lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)) )
        {
-               /* default lua prefix */
-               if( ! conf.lua_prefix )
-                       conf.lua_prefix = "/lua";
+               fprintf(stderr,
+                       "Notice: Unable to load Lua plugin - disabling Lua support! "
+                       "(Reason: %s)\n", dlerror()
+               );
+       }
+       else
+       {
+               /* resolve functions */
+               if( !(conf.lua_init    = dlsym(lua_lib, "uh_lua_init"))    ||
+                   !(conf.lua_close   = dlsym(lua_lib, "uh_lua_close"))   ||
+                   !(conf.lua_request = dlsym(lua_lib, "uh_lua_request"))
+               ) {
+                       fprintf(stderr,
+                               "Error: Failed to lookup required symbols "
+                               "in Lua plugin: %s\n", dlerror()
+                       );
+                       exit(1);
+               }
+
+               /* init Lua runtime if handler is specified */
+               if( conf.lua_handler )
+               {
+                       /* default lua prefix */
+                       if( ! conf.lua_prefix )
+                               conf.lua_prefix = "/lua";
 
-               L = uh_lua_init(conf.lua_handler);
+                       L = conf.lua_init(conf.lua_handler);
+               }
        }
 #endif
 
@@ -711,7 +788,8 @@ int main (int argc, char **argv)
                                                {
 #ifdef HAVE_TLS
                                                        /* setup client tls context */
-                                                       uh_tls_client_accept(cl);
+                                                       if( conf.tls )
+                                                               conf.tls_accept(cl);
 #endif
 
                                                        /* add client socket to global fdset */
@@ -753,7 +831,7 @@ int main (int argc, char **argv)
                                                /* Lua request? */
                                                if( L && uh_path_match(conf.lua_prefix, req->url) )
                                                {
-                                                       uh_lua_request(cl, req, L);
+                                                       conf.lua_request(cl, req, L);
                                                }
                                                else
 #endif
@@ -793,7 +871,8 @@ int main (int argc, char **argv)
 
 #ifdef HAVE_TLS
                                        /* free client tls context */
-                                       uh_tls_client_close(cl);
+                                       if( conf.tls )
+                                               conf.tls_close(cl);
 #endif
 
                                        cleanup:
@@ -812,7 +891,7 @@ int main (int argc, char **argv)
 #ifdef HAVE_LUA
        /* destroy the Lua state */
        if( L != NULL )
-               lua_close(L);
+               conf.lua_close(L);
 #endif
 
        return 0;
index d26835a70b937c78a2e4db683da34307acc46380..bb08afa1a14bd256545fbb2ab0cffe24e1cd1d75 100644 (file)
 #include <netdb.h>
 #include <ctype.h>
 
+#include <dlfcn.h>
+
+
+#ifdef HAVE_LUA
+#include <lua.h>
+#endif
+
 #ifdef HAVE_TLS
 #include <openssl/ssl.h>
 #endif
@@ -48,6 +55,9 @@
 #define UH_HTTP_MSG_HEAD       1
 #define UH_HTTP_MSG_POST       2
 
+struct listener;
+struct client;
+struct http_request;
 
 struct config {
        char docroot[PATH_MAX];
@@ -59,11 +69,22 @@ struct config {
 #ifdef HAVE_LUA
        char *lua_prefix;
        char *lua_handler;
+       lua_State * (*lua_init) (const char *handler);
+       void (*lua_close) (lua_State *L);
+       void (*lua_request) (struct client *cl, struct http_request *req, lua_State *L);
 #endif
 #ifdef HAVE_TLS
        char *cert;
        char *key;
        SSL_CTX *tls;
+       SSL_CTX * (*tls_init) (void);
+       int (*tls_cert) (SSL_CTX *c, const char *file);
+       int (*tls_key) (SSL_CTX *c, const char *file);
+       void (*tls_free) (struct listener *l);
+       void (*tls_accept) (struct client *c);
+       void (*tls_close) (struct client *c);
+       int (*tls_recv) (struct client *c, void *buf, int len);
+       int (*tls_send) (struct client *c, void *buf, int len);
 #endif
 };