lwsws cgi integration
authorAndy Green <andy@warmcat.com>
Wed, 13 Apr 2016 03:49:07 +0000 (11:49 +0800)
committerAndy Green <andy@warmcat.com>
Wed, 13 Apr 2016 03:53:40 +0000 (11:53 +0800)
Signed-off-by: Andy Green <andy@warmcat.com>
12 files changed:
README.lwsws.md
lib/context.c
lib/libuv.c
lib/libwebsockets.c
lib/libwebsockets.h
lib/lws-plat-unix.c
lib/private-libwebsockets.h
lib/server.c
lib/ssl-server.c
lwsws/conf.c
lwsws/http.c
test-server/test-server-http.c

index 4692a77..a49ee01 100644 (file)
@@ -140,8 +140,56 @@ Mounts
 Where mounts are given in the vhost definition, then directory contents may
 be auto-served if it matches the mountpoint.
 
-Currently only file:// mount protocol and a fixed set of mimetypes are
-supported.
+Mount protocols are used to control what kind of translation happens
+
+ - file://  serve the uri using the remainder of the url past the mountpoint based on the origin directory.
+
+ Eg, with this mountpoint
+
+```
+       {
+        "mountpoint": "/",
+        "origin": "file:///var/www/mysite.com",
+        "default": "/"
+       }
+```
+
+ The uri /file.jpg would serve /var/www/mysite.com/file.jpg, since / matched.
+
+ - ^http:// or ^https://  these cause any url matching the mountpoint to issue a redirect to the origin url
+
+ - cgi://   this causes any matching url to be given to the named cgi, eg
+
+```
+       {
+        "mountpoint": "/git",
+        "origin": "cgi:///var/www/cgi-bin/cgit",
+        "default": "/"
+       }, {
+        "mountpoint": "/cgit-data",
+        "origin": "file:///usr/share/cgit",
+        "default": "/"
+       },
+```
+
+ would cause the url /git/myrepo to pass "myrepo" to the cgi /var/www/cgi-bin/cgit and send the results to the client.
+
+ When using a cgi:// protcol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this
+
+```
+       {
+        "mountpoint": "/git",
+        "origin": "cgi:///var/www/cgi-bin/cgit",
+        "default": "/",
+        "cgi-env": [{
+                "CGIT_CONFIG": "/etc/cgitrc/libwebsockets.org"
+        }]
+       }
+```
+
+ This allows you to customize one cgi depending on the mountpoint (and / or vhost).
+
+Currently only a fixed set of mimetypes are supported.
 
 
 Plugins
index fb9aabf..d8a04a8 100644 (file)
@@ -52,7 +52,7 @@ static const char * const mount_protocols[] = {
 LWS_VISIBLE LWS_EXTERN int
 lws_write_http_mount(struct lws_http_mount *next, struct lws_http_mount **res,
                     void *store, const char *mountpoint, const char *origin,
-                    const char *def)
+                    const char *def, struct lws_protocol_vhost_options *cgienv)
 {
        struct lws_http_mount *m;
        void *orig = store;
@@ -70,6 +70,7 @@ lws_write_http_mount(struct lws_http_mount *next, struct lws_http_mount **res,
        m->mountpoint = mountpoint;
        m->mountpoint_len = (unsigned char)strlen(mountpoint);
        m->mount_next = NULL;
+       m->cgienv = cgienv;
        if (next)
                next->mount_next = m;
 
index 89ee690..6013e09 100644 (file)
@@ -51,11 +51,14 @@ lws_uv_idle(uv_idle_t *handle
                /* still somebody left who wants forced service? */
                if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
                        /* yes... come back again later */
+                       lwsl_debug("%s: done again\n", __func__);
                        return;
        }
 
        /* there is nobody who needs service forcing, shut down idle */
        uv_idle_stop(handle);
+
+       lwsl_debug("%s: done stop\n", __func__);
 }
 
 static void
@@ -272,7 +275,7 @@ lws_libuv_io(struct lws *wsi, int flags)
        if (!LWS_LIBUV_ENABLED(context))
                return;
 
-       lwsl_debug("%s: wsi: %p, flags:%d\n", __func__, wsi, flags);
+       lwsl_debug("%s: wsi: %p, flags:0x%x\n", __func__, wsi, flags);
 
        if (!pt->io_loop_uv) {
                lwsl_info("%s: no io loop yet\n", __func__);
index c537c1b..b85e6e9 100644 (file)
@@ -176,10 +176,11 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
        if (wsi->mode == LWSCM_CGI) {
                /* we are not a network connection, but a handler for CGI io */
                if (wsi->parent && wsi->parent->cgi)
-               /* end the binding between us and master */
-               wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
+                       /* end the binding between us and master */
+                       wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
                wsi->socket_is_permanently_unusable = 1;
 
+               lwsl_debug("------ %s: detected cgi fdhandler wsi %p\n", __func__, wsi);
                goto just_kill_connection;
        }
 
@@ -496,6 +497,7 @@ just_kill_connection:
 
 #ifdef LWS_USE_LIBUV
        if (LWS_LIBUV_ENABLED(context)) {
+               lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
                /* libuv has to do his own close handle processing asynchronously */
                lws_libuv_closehandle(wsi);
 
@@ -1534,7 +1536,7 @@ lws_urlencode(const char *in, int inlen, char *out, int outlen)
        const char *hex = "0123456789ABCDEF";
        char *start = out, *end = out + outlen;
 
-       while (inlen-- && out > end - 4) {
+       while (inlen-- && out < end - 4) {
                if ((*in >= 'A' && *in <= 'Z') ||
                    (*in >= 'a' && *in <= 'z') ||
                    (*in >= '0' && *in <= '9') ||
@@ -1635,12 +1637,12 @@ lws_create_basic_wsi(struct lws_context *context, int tsi)
  */
 
 LWS_VISIBLE LWS_EXTERN int
-lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len,
-       int timeout_secs)
+lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len,
+       int timeout_secs, struct lws_protocol_vhost_options *mp_cgienv)
 {
        struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
        char *env_array[30], cgi_path[400], e[1024], *p = e,
-            *end = p + sizeof(e) - 1, tok[256];
+            *end = p + sizeof(e) - 1, tok[256], *t;
        struct lws_cgi *cgi;
        int n, m, i;
 
@@ -1670,12 +1672,15 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len,
                if (!cgi->stdwsi[n])
                        goto bail2;
                cgi->stdwsi[n]->cgi_channel = n;
+               cgi->stdwsi[n]->vhost = wsi->vhost;
+
                /* read side is 0, stdin we want the write side, others read */
                cgi->stdwsi[n]->sock = cgi->pipe_fds[n][!!(n == 0)];
                fcntl(cgi->pipe_fds[n][!!(n == 0)], F_SETFL, O_NONBLOCK);
        }
 
        for (n = 0; n < 3; n++) {
+               lws_libuv_accept(cgi->stdwsi[n], cgi->stdwsi[n]->sock);
                if (insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
                        goto bail3;
                cgi->stdwsi[n]->parent = wsi;
@@ -1725,9 +1730,16 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len,
                                             WSI_TOKEN_HTTP_URI_ARGS, m);
                        if (i < 0)
                                break;
-                       i = lws_urlencode(tok, i, p, end - p);
-                       p += i;
-                       *p++ = '&';
+                       t = tok;
+                       while (*t && *t != '=' && p < end - 4)
+                               *p++ = *t++;
+                       if (*t == '=')
+                               *p++ = *t++;
+                       i = lws_urlencode(t, i- (t - tok), p, end - p);
+                       if (i > 0) {
+                               p += i;
+                               *p++ = '&';
+                       }
                        m++;
                }
                if (m)
@@ -1759,13 +1771,23 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len,
                p++;
        }
        env_array[n++] = p;
-       p += snprintf(p, end - p, "SCRIPT_PATH=%s", exec_array[2]) + 1;
+       p += snprintf(p, end - p, "SCRIPT_PATH=%s", exec_array[0]) + 1;
+
+       while (mp_cgienv) {
+               env_array[n++] = p;
+               p += snprintf(p, end - p, "%s=%s", mp_cgienv->name,
+                             mp_cgienv->value);
+               lwsl_notice("   Applying mount-specific cgi env '%s'\n",
+                           env_array[n - 1]);
+               p++;
+               mp_cgienv = mp_cgienv->next;
+       }
 
        env_array[n++] = "SERVER_SOFTWARE=libwebsockets";
        env_array[n++] = "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin";
        env_array[n] = NULL;
 
-#if 0
+#if 1
        for (m = 0; m < n; m++)
                lwsl_err("    %s\n", env_array[m]);
 #endif
@@ -1785,6 +1807,10 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len,
                /* we are the parent process */
                return 0;
 
+       /* somewhere we can at least read things and enter it */
+       if (chdir("/"))
+               lwsl_notice("%s: Failed to chdir\n", __func__);
+
        /* We are the forked process, redirect and kill inherited things.
         *
         * Because of vfork(), we cannot do anything that changes pages in
@@ -1806,9 +1832,9 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len,
                *p++ = '\0';
                setenv(env_array[m], p, 1);
        }
-       execvp(exec_array[0], &exec_array[0]);
+       execvp(exec_array[0], (char * const *)&exec_array[0]);
 #else
-       execvpe(exec_array[0], &exec_array[0], &env_array[0]);
+       execvpe(exec_array[0], (char * const *)&exec_array[0], &env_array[0]);
 #endif
 
        exit(1);
@@ -1948,6 +1974,8 @@ lws_cgi_kill(struct lws *wsi)
        struct lws_cgi_args args;
        int n, status, do_close = 0;
 
+       lwsl_debug("!!!!! %s: %p\n", __func__, wsi);
+
        if (!wsi->cgi)
                return 0;
 
@@ -1986,17 +2014,20 @@ lws_cgi_kill(struct lws *wsi)
                pcgi = &(*pcgi)->cgi_list;
        }
 
-       for (n = 0 ; n < 3; n++) {
-               if (wsi->cgi->pipe_fds[n][!!(n == 0)] >= 0) {
-                       close(wsi->cgi->pipe_fds[n][!!(n == 0)]);
-                       wsi->cgi->pipe_fds[n][!!(n == 0)] = -1;
+       if (!do_close)
+               for (n = 0 ; n < 3; n++) {
+                       if (wsi->cgi->pipe_fds[n][!!(n == 0)] >= 0) {
+                               close(wsi->cgi->pipe_fds[n][!!(n == 0)]);
+                               wsi->cgi->pipe_fds[n][!!(n == 0)] = -1;
+                       }
                }
-       }
 
        lws_free_set_NULL(wsi->cgi);
 
-       if (do_close)
+       if (do_close) {
+               lwsl_debug("!!!!! %s: do_close\n", __func__);
                lws_close_free_wsi(wsi, 0);
+       }
 
        return 0;
 }
index 13d8bcc..9996cf2 100644 (file)
@@ -1538,10 +1538,20 @@ struct lws_client_connect_info {
 
 struct lws_http_mount;
 
+enum {
+       LWSMPRO_HTTP,
+       LWSMPRO_HTTPS,
+       LWSMPRO_FILE,
+       LWSMPRO_CGI,
+       LWSMPRO_REDIR_HTTP,
+       LWSMPRO_REDIR_HTTPS,
+};
+
 LWS_VISIBLE LWS_EXTERN int
 lws_write_http_mount(struct lws_http_mount *next, struct lws_http_mount **res,
                     void *store, const char *mountpoint, const char *origin,
-                    const char *def);
+                    const char *def,
+                    struct lws_protocol_vhost_options *cgienv);
 
 LWS_VISIBLE LWS_EXTERN void
 lws_set_log_level(int level,
@@ -2012,8 +2022,9 @@ struct lws_cgi_args {
 };
 
 LWS_VISIBLE LWS_EXTERN int
-lws_cgi(struct lws *wsi, char * const *exec_array,  int script_uri_path_len,
-       int timeout_secs);
+lws_cgi(struct lws *wsi, const char * const *exec_array,
+       int script_uri_path_len, int timeout_secs,
+       struct lws_protocol_vhost_options *mp_cgienv);
 
 LWS_VISIBLE LWS_EXTERN int
 lws_cgi_write_split_stdout_headers(struct lws *wsi);
index eb2f762..880ad85 100644 (file)
@@ -441,8 +441,10 @@ next:
 
 
 static void
-sigpipe_handler(int x)
+sigabrt_handler(int x)
 {
+       printf("%s\n", __func__);
+       //*(char *)0 = 0;
 }
 
 LWS_VISIBLE int
@@ -456,7 +458,9 @@ lws_plat_context_early_init(void)
 
        sigprocmask(SIG_BLOCK, &mask, NULL);
 
-       signal(SIGPIPE, sigpipe_handler);
+       signal(SIGPIPE, SIG_IGN);
+
+       signal(SIGABRT, sigabrt_handler);
 
        return 0;
 }
index 35f3ed6..0684326 100644 (file)
@@ -621,6 +621,8 @@ struct lws_http_mount {
        const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */
        const char *def; /* default target, eg, "index.html" */
 
+       struct lws_protocol_vhost_options *cgienv;
+
        unsigned char origin_protocol;
        unsigned char mountpoint_len;
 };
index f1ca7ac..b28c9bb 100644 (file)
@@ -218,17 +218,48 @@ static const char * get_mimetype(const char *file)
 int lws_http_serve(struct lws *wsi, char *uri, const char *origin)
 {
        const char *mimetype;
-       char path[256];
-       int n;
+       struct stat st;
+       char path[256], sym[256];
+       int n, spin = 0;
 
        lwsl_notice("%s: %s %s\n", __func__, uri, origin);
        snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
 
+       do {
+               spin++;
+
+               if (stat(path, &st)) {
+                       lwsl_err("unable to stat %s\n", path);
+                       goto bail;
+               }
+
+               lwsl_debug(" %s mode %d\n", path, S_IFMT & st.st_mode);
+
+               if ((S_IFMT & st.st_mode) == S_IFLNK) {
+                       if (readlink(path, sym, sizeof(sym))) {
+                               lwsl_err("Failed to read link %s\n", path);
+                               goto bail;
+                       }
+                       lwsl_debug("symlink %s -> %s\n", path, sym);
+                       snprintf(path, sizeof(path) - 1, "%s", sym);
+               }
+
+               if ((S_IFMT & st.st_mode) == S_IFDIR) {
+                       lwsl_debug("default filename append to dir\n");
+                       snprintf(path, sizeof(path) - 1, "%s/%s/index.html",
+                                origin, uri);
+               }
+
+       } while ((S_IFMT & st.st_mode) != S_IFREG && spin < 5);
+
+       if (spin == 5) {
+               lwsl_err("symlink loop %s \n", path);
+       }
+
        mimetype = get_mimetype(path);
        if (!mimetype) {
                lwsl_err("unknown mimetype for %s", path);
-               lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
-               return -1;
+               goto bail;
        }
 
        n = lws_serve_http_file(wsi, path, mimetype, NULL, 0);
@@ -237,6 +268,10 @@ int lws_http_serve(struct lws *wsi, char *uri, const char *origin)
                return -1; /* error or can't reuse connection: close the socket */
 
        return 0;
+bail:
+       lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
+
+       return -1;
 }
 
 int
@@ -403,7 +438,11 @@ lws_http_action(struct lws *wsi)
        hm = wsi->vhost->mount_list;
        while (hm) {
                if (uri_len >= hm->mountpoint_len &&
-                   !strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len)) {
+                   !strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len) &&
+                   (uri_ptr[hm->mountpoint_len] == '\0' ||
+                    uri_ptr[hm->mountpoint_len] == '/' ||
+                    hm->mountpoint_len == 1)
+                   ) {
                        if (hm->mountpoint_len > best) {
                                best = hm->mountpoint_len;
                                hit = hm;
@@ -414,7 +453,8 @@ lws_http_action(struct lws *wsi)
        if (hit) {
                char *s = uri_ptr + hit->mountpoint_len;
 
-               lwsl_err("*** hit %d %d %s\n", hit->mountpoint_len, hit->origin_protocol , hit->origin);
+               lwsl_debug("*** hit %d %d %s\n", hit->mountpoint_len,
+                          hit->origin_protocol , hit->origin);
 
                /*
                 * if we have a mountpoint like https://xxx.com/yyy
@@ -431,50 +471,87 @@ lws_http_action(struct lws *wsi)
                 * / at the end, we must redirect to add it so the browser
                 * understands he is one "directory level" down.
                 */
-               if (hit->mountpoint_len > 1 || (hit->origin_protocol & 4))
-                       if (*s != '/' || (hit->origin_protocol & 4)) {
-                               unsigned char *start = pt->serv_buf + LWS_PRE,
+               if ((hit->mountpoint_len > 1 || (hit->origin_protocol & 4)) &&
+                   (*s != '/' || (hit->origin_protocol & 4))) {
+                       unsigned char *start = pt->serv_buf + LWS_PRE,
                                              *p = start, *end = p + 512;
-                               static const char *oprot[] = {
-                                       "http://", "https://"
-                               };
-
-                               if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
-                                       goto bail_nuke_ah;
-                               if (lws_add_http_header_status(wsi, 301, &p, end))
-                                       goto bail_nuke_ah;
-
-                               lwsl_err("**** %s", hit->origin);
-
-                               /* > at start indicates deal with by redirect */
-                               if (hit->origin_protocol & 4)
-                                       n = snprintf((char *)end, 256, "%s%s",
-                                                   oprot[hit->origin_protocol & 1],
-                                                   hit->origin);
-                               else
-                                       n = snprintf((char *)end, 256,
-                                           "https://%s/%s/",
-                                           lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
-                                           uri_ptr);
-                               if (lws_add_http_header_by_token(wsi,
-                                               WSI_TOKEN_HTTP_LOCATION,
-                                               end, n, &p, end))
-                                       goto bail_nuke_ah;
-                               if (lws_finalize_http_header(wsi, &p, end))
-                                       goto bail_nuke_ah;
-                               n = lws_write(wsi, start, p - start,
-                                               LWS_WRITE_HTTP_HEADERS);
-                               if ((int)n < 0)
-                                       goto bail_nuke_ah;
-
-                               return lws_http_transaction_completed(wsi);
+                       static const char *oprot[] = {
+                               "http://", "https://"
+                       };
+
+                       if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
+                               goto bail_nuke_ah;
+                       if (lws_add_http_header_status(wsi, 301, &p, end))
+                               goto bail_nuke_ah;
+
+                       lwsl_debug("**** %s", hit->origin);
+
+                       /* > at start indicates deal with by redirect */
+                       if (hit->origin_protocol & 4)
+                               n = snprintf((char *)end, 256, "%s%s",
+                                           oprot[hit->origin_protocol & 1],
+                                           hit->origin);
+                       else
+                               n = snprintf((char *)end, 256,
+                                   "https://%s/%s/",
+                                   lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
+                                   uri_ptr);
+                       if (lws_add_http_header_by_token(wsi,
+                                       WSI_TOKEN_HTTP_LOCATION,
+                                       end, n, &p, end))
+                               goto bail_nuke_ah;
+                       if (lws_finalize_http_header(wsi, &p, end))
+                               goto bail_nuke_ah;
+                       n = lws_write(wsi, start, p - start,
+                                       LWS_WRITE_HTTP_HEADERS);
+                       if ((int)n < 0)
+                               goto bail_nuke_ah;
+
+                       return lws_http_transaction_completed(wsi);
+               }
+
+#ifdef LWS_WITH_CGI
+               /* did we hit something with a cgi:// origin? */
+               if (hit->origin_protocol == LWSMPRO_CGI) {
+                       const char *cmd[] = {
+                               NULL, /* replace with cgi path */
+                               NULL
+                       };
+                       unsigned char *p, *end, buffer[256];
+
+                       lwsl_debug("%s: cgi\n", __func__);
+                       cmd[0] = hit->origin;
+                       n = lws_cgi(wsi, cmd, hit->mountpoint_len, 5,
+                                   hit->cgienv);
+                       if (n) {
+                               lwsl_err("%s: cgi failed\n");
+                               return -1;
                        }
+                       p = buffer + LWS_PRE;
+                       end = p + sizeof(buffer) - LWS_PRE;
+
+                       if (lws_add_http_header_status(wsi, 200, &p, end))
+                               return 1;
+                       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
+                                       (unsigned char *)"close", 5, &p, end))
+                               return 1;
+                       n = lws_write(wsi, buffer + LWS_PRE,
+                                     p - (buffer + LWS_PRE),
+                                     LWS_WRITE_HTTP_HEADERS);
+
+                       return 0;
+               }
+#endif
 
-               if (s[0] == '\0' || (s[0] == '/' && s[1] == '\0'))
+               n = strlen(s);
+               if (s[0] == '\0' || (n == 1 && s[n - 1] == '/'))
                        s = (char *)hit->def;
 
                if (!s)
                        s = "index.html";
+
+
+
                n = lws_http_serve(wsi, s, hit->origin);
        } else
                n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
@@ -992,18 +1069,21 @@ lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
        lws_libuv_accept(new_wsi, new_wsi->sock);
 
        if (!LWS_SSL_ENABLED(new_wsi->vhost)) {
-               if (insert_wsi_socket_into_fds(context, new_wsi))
+               if (insert_wsi_socket_into_fds(context, new_wsi)) {
+                       lwsl_err("%s: fail inserting socket\n", __func__);
                        goto fail;
+               }
        } else {
                new_wsi->mode = LWSCM_SSL_INIT;
-               if (lws_server_socket_service_ssl(new_wsi, accept_fd))
+               if (lws_server_socket_service_ssl(new_wsi, accept_fd)) {
+                       lwsl_err("%s: fail ssl negotiation\n", __func__);
                        goto fail;
+               }
        }
 
        return new_wsi;
 
 fail:
-       lwsl_err("%s: fail\n", __func__);
        lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);
 
        return NULL;
index 9bd2af9..55ff61b 100644 (file)
@@ -178,7 +178,8 @@ lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
        if (servername) {
                vhost = lws_select_vhost(context, port, servername);
                if (vhost) {
-                       lwsl_notice("SNI: Found: %s (port %d)\n", servername, port);
+                       lwsl_debug("SNI: Found: %s (port %d)\n",
+                                  servername, port);
                        SSL_set_SSL_CTX(ssl, vhost->ssl_ctx);
                        return SSL_TLSEXT_ERR_OK;
                }
index ff4029d..1cbc5ed 100644 (file)
@@ -48,6 +48,7 @@ static const char * const paths_vhosts[] = {
        "vhosts[].mounts[].mountpoint",
        "vhosts[].mounts[].origin",
        "vhosts[].mounts[].default",
+       "vhosts[].mounts[].cgi-env[].*",
        "vhosts[].ws-protocols[].*.*",
        "vhosts[].ws-protocols[].*",
        "vhosts[].ws-protocols[]",
@@ -64,6 +65,7 @@ enum lejp_vhost_paths {
        LEJPVP_MOUNTPOINT,
        LEJPVP_ORIGIN,
        LEJPVP_DEFAULT,
+       LEJPVP_CGI_ENV,
        LEJPVP_PROTOCOL_NAME_OPT,
        LEJPVP_PROTOCOL_NAME,
        LEJPVP_PROTOCOL,
@@ -78,6 +80,7 @@ struct jpargs {
        struct lws_http_mount *head, *last;
        char *mountpoint, *origin, *def;
        struct lws_protocol_vhost_options *pvo;
+       struct lws_protocol_vhost_options *mp_cgienv;
 };
 
 static void *
@@ -144,13 +147,15 @@ static char
 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
 {
        struct jpargs *a = (struct jpargs *)ctx->user;
-       struct lws_protocol_vhost_options *pvo;
+       struct lws_protocol_vhost_options *pvo, *mp_cgienv;
        struct lws_http_mount *m;
        int n;
 
-//     lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
-//     for (n = 0; n < ctx->wildcount; n++)
-//             lwsl_notice("    %d\n", ctx->wild[n]);
+#if 0
+       lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
+       for (n = 0; n < ctx->wildcount; n++)
+               lwsl_notice("    %d\n", ctx->wild[n]);
+#endif
 
        if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
                /* set the defaults for this vhost */
@@ -186,6 +191,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                a->mountpoint = NULL;
                a->origin = NULL;
                a->def = NULL;
+               a->mp_cgienv = NULL;
        }
 
        /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
@@ -235,7 +241,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                }
 
                n = lws_write_http_mount(a->last, &m, a->p, a->mountpoint,
-                                        a->origin, a->def);
+                                        a->origin, a->def, a->mp_cgienv);
                if (!n)
                        return 1;
                a->p += n;
@@ -274,7 +280,25 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
        case LEJPVP_DEFAULT:
                a->def = a->p;
                break;
+       case LEJPVP_CGI_ENV:
+               mp_cgienv = lwsws_align(a);
+               a->p += sizeof(*a->mp_cgienv);
+
+               mp_cgienv->next = a->mp_cgienv;
+               a->mp_cgienv = mp_cgienv;
 
+               n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
+               mp_cgienv->name = a->p;
+               a->p += n;
+               mp_cgienv->value = a->p;
+               mp_cgienv->options = NULL;
+               a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
+               *(a->p)++ = '\0';
+
+               lwsl_notice("    adding cgi-env '%s' = '%s'\n", mp_cgienv->name,
+                               mp_cgienv->value);
+
+               break;
        case LEJPVP_PROTOCOL_NAME_OPT:
                /* this catches, eg,
                 * vhosts[].ws-protocols[].xxx-protocol.yyy-option
@@ -435,7 +459,7 @@ lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
 
        a.info = info;
        a.p = *cs;
-       a.end = a.p + *len;
+       a.end = (a.p + *len) - 1;
        a.valid = 0;
 
        if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_global,
index 66f398f..ff4ca98 100644 (file)
@@ -152,42 +152,6 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                }
 #endif
 
-#ifdef LWS_WITH_CGI
-               if (!strncmp(in, "/cgitest", 8)) {
-                       static char *cmd[] = {
-                               "/bin/sh",
-                               "-c",
-                               INSTALL_DATADIR"/libwebsockets-test-server/lws-cgi-test.sh",
-//                             "/var/www/cgi-bin/cgit",
-                               NULL
-                       };
-
-                       lwsl_notice("%s: cgitest\n", __func__);
-                       n = lws_cgi(wsi, cmd, 8, 5);
-                       if (n) {
-                               lwsl_err("%s: cgi failed\n");
-                               return -1;
-                       }
-                       p = buffer + LWS_PRE;
-                       end = p + sizeof(buffer) - LWS_PRE;
-
-                       if (lws_add_http_header_status(wsi, 200, &p, end))
-                               return 1;
-                       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
-                                       (unsigned char *)"close", 5, &p, end))
-                               return 1;
-                       n = lws_write(wsi, buffer + LWS_PRE,
-                                     p - (buffer + LWS_PRE),
-                                     LWS_WRITE_HTTP_HEADERS);
-
-                       /* the cgi starts by outputting headers, we can't
-                        *  finalize the headers until we see the end of that
-                        */
-
-                       break;
-               }
-#endif
-
                /* if a legal POST URL, let it continue and accept data */
                if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
                        return 0;
index 902e945..af40609 100644 (file)
@@ -215,42 +215,6 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                }
 #endif
 
-#ifdef LWS_WITH_CGI
-               if (!strncmp(in, "/cgitest", 8)) {
-                       static char *cmd[] = {
-                               "/bin/sh",
-                               "-c",
-                               INSTALL_DATADIR"/libwebsockets-test-server/lws-cgi-test.sh",
-//                             "/var/www/cgi-bin/cgit",
-                               NULL
-                       };
-
-                       lwsl_notice("%s: cgitest\n", __func__);
-                       n = lws_cgi(wsi, cmd, 8, 5);
-                       if (n) {
-                               lwsl_err("%s: cgi failed\n");
-                               return -1;
-                       }
-                       p = buffer + LWS_PRE;
-                       end = p + sizeof(buffer) - LWS_PRE;
-
-                       if (lws_add_http_header_status(wsi, 200, &p, end))
-                               return 1;
-                       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
-                                       (unsigned char *)"close", 5, &p, end))
-                               return 1;
-                       n = lws_write(wsi, buffer + LWS_PRE,
-                                     p - (buffer + LWS_PRE),
-                                     LWS_WRITE_HTTP_HEADERS);
-
-                       /* the cgi starts by outputting headers, we can't
-                        *  finalize the headers until we see the end of that
-                        */
-
-                       break;
-               }
-#endif
-
                /* if a legal POST URL, let it continue and accept data */
                if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
                        return 0;
@@ -423,15 +387,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 
                if (pss->fd == LWS_INVALID_FILE)
                        goto try_to_reuse;
-#ifdef LWS_WITH_CGI
-               if (pss->reason_bf & 1) {
-                       if (lws_cgi_write_split_stdout_headers(wsi) < 0)
-                               goto bail;
 
-                       pss->reason_bf &= ~1;
-                       break;
-               }
-#endif
 #ifndef LWS_NO_CLIENT
                if (pss->reason_bf & 2) {
                        char *px = buf + LWS_PRE;
@@ -601,56 +557,6 @@ bail:
                break;
 #endif
 
-#ifdef LWS_WITH_CGI
-       /* CGI IO events (POLLIN/OUT) appear here our demo user code policy is
-        *
-        *  - POST data goes on subprocess stdin
-        *  - subprocess stdout goes on http via writeable callback
-        *  - subprocess stderr goes to the logs
-        */
-       case LWS_CALLBACK_CGI:
-               pss->args = *((struct lws_cgi_args *)in);
-               //lwsl_notice("LWS_CALLBACK_CGI: ch %d\n", pss->args.ch);
-               switch (pss->args.ch) { /* which of stdin/out/err ? */
-               case LWS_STDIN:
-                       /* TBD stdin rx flow control */
-                       break;
-               case LWS_STDOUT:
-                       pss->reason_bf |= 1;
-                       /* when writing to MASTER would not block */
-                       lws_callback_on_writable(wsi);
-                       break;
-               case LWS_STDERR:
-                       n = read(lws_get_socket_fd(pss->args.stdwsi[LWS_STDERR]),
-                                       buf, 127);
-                       //lwsl_notice("stderr reads %d\n", n);
-                       if (n > 0) {
-                               if (buf[n - 1] != '\n')
-                                       buf[n++] = '\n';
-                               buf[n] = '\0';
-                               lwsl_notice("CGI-stderr: %s\n", buf);
-                       }
-                       break;
-               }
-               break;
-
-       case LWS_CALLBACK_CGI_TERMINATED:
-               //lwsl_notice("LWS_CALLBACK_CGI_TERMINATED\n");
-               /* because we sent on openended http, close the connection */
-               return -1;
-
-       case LWS_CALLBACK_CGI_STDIN_DATA:  /* POST body for stdin */
-               //lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA\n");
-               pss->args = *((struct lws_cgi_args *)in);
-               n = write(lws_get_socket_fd(pss->args.stdwsi[LWS_STDIN]),
-                         pss->args.data, pss->args.len);
-               //lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: write says %d", n);
-               if (n < pss->args.len)
-                       lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: sent %d only %d went",
-                                       n, pss->args.len);
-               return n;
-#endif
-
        /*
         * callbacks for managing the external poll() array appear in
         * protocol 0 callback