lwsws cgi integration
Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
parent
6e7b79b263
commit
a5e73a1a4b
12 changed files with 282 additions and 207 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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__);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
164
lib/server.c
164
lib/server.c
|
@ -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://"
|
||||
};
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
/* > 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);
|
||||
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 (s[0] == '\0' || (s[0] == '/' && s[1] == '\0'))
|
||||
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
|
||||
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
36
lwsws/conf.c
36
lwsws/conf.c
|
@ -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,
|
||||
|
|
36
lwsws/http.c
36
lwsws/http.c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue