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
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;
m->mountpoint = mountpoint;
m->mountpoint_len = (unsigned char)strlen(mountpoint);
m->mount_next = NULL;
+ m->cgienv = cgienv;
if (next)
next->mount_next = m;
/* 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
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__);
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;
}
#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);
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') ||
*/
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;
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;
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)
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
/* 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
*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);
struct lws_cgi_args args;
int n, status, do_close = 0;
+ lwsl_debug("!!!!! %s: %p\n", __func__, wsi);
+
if (!wsi->cgi)
return 0;
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;
}
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,
};
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);
static void
-sigpipe_handler(int x)
+sigabrt_handler(int x)
{
+ printf("%s\n", __func__);
+ //*(char *)0 = 0;
}
LWS_VISIBLE int
sigprocmask(SIG_BLOCK, &mask, NULL);
- signal(SIGPIPE, sigpipe_handler);
+ signal(SIGPIPE, SIG_IGN);
+
+ signal(SIGABRT, sigabrt_handler);
return 0;
}
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;
};
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);
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
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;
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
* / 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,
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;
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;
}
"vhosts[].mounts[].mountpoint",
"vhosts[].mounts[].origin",
"vhosts[].mounts[].default",
+ "vhosts[].mounts[].cgi-env[].*",
"vhosts[].ws-protocols[].*.*",
"vhosts[].ws-protocols[].*",
"vhosts[].ws-protocols[]",
LEJPVP_MOUNTPOINT,
LEJPVP_ORIGIN,
LEJPVP_DEFAULT,
+ LEJPVP_CGI_ENV,
LEJPVP_PROTOCOL_NAME_OPT,
LEJPVP_PROTOCOL_NAME,
LEJPVP_PROTOCOL,
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 *
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 */
a->mountpoint = NULL;
a->origin = NULL;
a->def = NULL;
+ a->mp_cgienv = NULL;
}
/* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
}
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;
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
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,
}
#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;
}
#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;
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;
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