uhttpd: make Lua handler more CGI like and fork child away
[project/luci.git] / contrib / package / uhttpd / src / uhttpd.c
index 54c16a8..ea4ca00 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * uhttpd - Tiny non-forking httpd - Main component
+ * uhttpd - Tiny single-threaded httpd - Main component
  *
  *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
  *
@@ -16,6 +16,8 @@
  *  limitations under the License.
  */
 
+#define _XOPEN_SOURCE 500      /* crypt() */
+
 #include "uhttpd.h"
 #include "uhttpd-utils.h"
 #include "uhttpd-file.h"
@@ -40,6 +42,43 @@ static void uh_sigterm(int sig)
        run = 0;
 }
 
+static void uh_config_parse(const char *path)
+{
+       FILE *c;
+       char line[512];
+       char *user = NULL;
+       char *pass = NULL;
+       char *eol  = NULL;
+
+       if( (c = fopen(path ? path : "/etc/httpd.conf", "r")) != NULL )
+       {
+               memset(line, 0, sizeof(line));
+
+               while( fgets(line, sizeof(line) - 1, c) )
+               {
+                       if( (line[0] == '/') && (strchr(line, ':') != NULL) )
+                       {
+                               if( !(user = strchr(line, ':')) || (*user++ = 0) ||
+                                   !(pass = strchr(user, ':')) || (*pass++ = 0) ||
+                                       !(eol = strchr(pass, '\n')) || (*eol++  = 0) )
+                                               continue;
+
+                               if( !uh_auth_add(line, user, pass) )
+                               {
+                                       fprintf(stderr,
+                                               "Can not manage more than %i basic auth realms, "
+                                               "will skip the rest\n", UH_LIMIT_AUTHREALMS
+                                       );
+
+                                       break;
+                               } 
+                       }
+               }
+
+               fclose(c);
+       }
+}
+
 static int uh_socket_bind(
        fd_set *serv_fds, int *max_fd, const char *host, const char *port,
        struct addrinfo *hints, int do_tls, struct config *conf
@@ -268,7 +307,7 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe
 
 static struct http_request * uh_http_header_recv(struct client *cl)
 {
-       char buffer[UH_LIMIT_MSGHEAD];
+       static char buffer[UH_LIMIT_MSGHEAD];
        char *bufptr = &buffer[0];
        char *idxptr = NULL;
 
@@ -333,6 +372,19 @@ static struct http_request * uh_http_header_recv(struct client *cl)
        return NULL;
 }
 
+static int uh_path_match(const char *prefix, const char *url)
+{
+       if( (strstr(url, prefix) == url) &&
+           ((prefix[strlen(prefix)-1] == '/') ||
+                (strlen(url) == strlen(prefix))   ||
+                (url[strlen(prefix)] == '/'))
+       ) {
+               return 1;
+       }
+
+       return 0;
+}
+
 
 int main (int argc, char **argv)
 {
@@ -347,7 +399,7 @@ int main (int argc, char **argv)
        /* working structs */
        struct addrinfo hints;
        struct http_request *req;
-       struct uh_path_info *pin;
+       struct path_info *pin;
        struct client *cl;
        struct sigaction sa;
        struct config conf;
@@ -398,7 +450,7 @@ int main (int argc, char **argv)
        }
 #endif
 
-       while( (opt = getopt(argc, argv, "fC:K:p:s:h:c:l:L:d:")) > 0 )
+       while( (opt = getopt(argc, argv, "fC:K:p:s:h:c:l:L:d:r:m:x:")) > 0 )
        {
                switch(opt)
                {
@@ -467,7 +519,7 @@ int main (int argc, char **argv)
 
 #ifdef HAVE_CGI
                        /* cgi prefix */
-                       case 'c':
+                       case 'x':
                                conf.cgi_prefix = optarg;
                                break;
 #endif
@@ -501,25 +553,44 @@ int main (int argc, char **argv)
                                }
                                break;
 
+                       /* basic auth realm */
+                       case 'r':
+                               conf.realm = optarg;
+                               break;
+
+                       /* md5 crypt */
+                       case 'm':
+                               printf("%s\n", crypt(optarg, "$1$"));
+                               exit(0);
+                               break;
+
+                       /* config file */
+                       case 'c':
+                               conf.file = optarg;
+                               break;
+
                        default:
                                fprintf(stderr,
                                        "Usage: %s -p [addr:]port [-h docroot]\n"
-                                       "       -p      Bind to specified address and port, multiple allowed\n"
+                                       "       -f              Do not fork to background\n"
+                                       "       -c file         Configuration file, default is '/etc/httpd.conf'\n"
+                                       "       -p [addr:]port  Bind to specified address and port, multiple allowed\n"
 #ifdef HAVE_TLS
-                                       "       -s      Like -p but provide HTTPS on this port\n"
-                                       "       -C      ASN.1 server certificate file\n"
-                                       "       -K      ASN.1 server private key file\n"
+                                       "       -s [addr:]port  Like -p but provide HTTPS on this port\n"
+                                       "       -C file         ASN.1 server certificate file\n"
+                                       "       -K file         ASN.1 server private key file\n"
 #endif
-                                       "       -h      Specify the document root, default is '.'\n"
-                                       "       -f      Do not fork to background\n"
+                                       "       -h directory    Specify the document root, default is '.'\n"
 #ifdef HAVE_LUA
-                                       "       -l      URL prefix for Lua handler, default is '/lua'\n"
-                                       "       -L      Lua handler script, omit to disable Lua\n"
+                                       "       -l string       URL prefix for Lua handler, default is '/lua'\n"
+                                       "       -L file         Lua handler script, omit to disable Lua\n"
 #endif
 #ifdef HAVE_CGI
-                                       "       -c      URL prefix for CGI handler, default is '/cgi-bin'\n"
+                                       "       -x string       URL prefix for CGI handler, default is '/cgi-bin'\n"
 #endif
-                                       "       -d      URL decode given string\n"
+                                       "       -d string       URL decode given string\n"
+                                       "       -r string       Specify basic auth realm\n"
+                                       "       -m string       MD5 crypt given string\n"
                                        "\n", argv[0]
                                );
 
@@ -549,6 +620,13 @@ int main (int argc, char **argv)
                exit(1);
        }
 
+       /* default realm */
+       if( ! conf.realm )
+               conf.realm = "Protected Area";
+
+       /* config file */
+       uh_config_parse(conf.file);
+
 #ifdef HAVE_CGI
        /* default cgi prefix */
        if( ! conf.cgi_prefix )
@@ -668,27 +746,33 @@ int main (int argc, char **argv)
                                        /* parse message header */
                                        if( (req = uh_http_header_recv(cl)) != NULL )
                                        {
+#ifdef HAVE_LUA
+                                               /* Lua request? */
+                                               if( L && uh_path_match(conf.lua_prefix, req->url) )
+                                               {
+                                                       uh_lua_request(cl, req, L);
+                                               }
+                                               else
+#endif
                                                /* dispatch request */
                                                if( (pin = uh_path_lookup(cl, req->url)) != NULL )
                                                {
-#ifdef HAVE_CGI
-                                                       if( strstr(pin->name, conf.cgi_prefix) == pin->name )
+                                                       /* auth ok? */
+                                                       if( uh_auth_check(cl, req, pin) )
                                                        {
-                                                               uh_cgi_request(cl, req, pin);
-                                                       }
-                                                       else
+#ifdef HAVE_CGI
+                                                               if( uh_path_match(conf.cgi_prefix, pin->name) )
+                                                               {
+                                                                       uh_cgi_request(cl, req, pin);
+                                                               }
+                                                               else
 #endif
-                                                       {
-                                                               uh_file_request(cl, req, pin);
+                                                               {
+                                                                       uh_file_request(cl, req, pin);
+                                                               }
                                                        }
                                                }
-#ifdef HAVE_LUA
-                                               /* Lua request? */
-                                               else if( strstr(req->url, conf.lua_prefix) == req->url )
-                                               {
-                                                       uh_lua_request(cl, req, L);
-                                               }
-#endif
+
                                                /* 404 */
                                                else
                                                {