- LWS_METHOD=http2 CMAKE_ARGS="-DLWS_WITH_HTTP2=ON"
- LWS_METHOD=nossl CMAKE_ARGS="-DLWS_WITH_SSL=OFF"
- LWS_METHOD=nodaemon CMAKE_ARGS="-DLWS_WITHOUT_DAEMONIZE=ON"
+ - LWS_METHOD=cgi CMAKE_ARGS="-DLWS_WITH_CGI=ON"
+
os:
- linux
- osx
CHECK_FUNCTION_EXISTS(socket LWS_HAVE_SOCKET)
CHECK_FUNCTION_EXISTS(strerror LWS_HAVE_STRERROR)
CHECK_FUNCTION_EXISTS(vfork LWS_HAVE_VFORK)
+CHECK_FUNCTION_EXISTS(execvpe LWS_HAVE_EXECVPE)
CHECK_FUNCTION_EXISTS(getifaddrs LWS_HAVE_GETIFADDRS)
CHECK_FUNCTION_EXISTS(snprintf LWS_HAVE_SNPRINTF)
CHECK_FUNCTION_EXISTS(_snprintf LWS_HAVE__SNPRINTF)
a simple api.
LWS_VISIBLE LWS_EXTERN int
-lws_cgi(struct lws *wsi, char * const *exec_array, int timeout_secs);
+lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len,
+ int timeout_secs);
LWS_VISIBLE LWS_EXTERN int
lws_cgi_kill(struct lws *wsi);
lwstest script
read="hello"
+The test script returns text/html table showing /proc/meminfo. But the cgi
+support is complete enough to run cgit cgi.
+
4) There is a helper api for forming logging timestamps
LWS_VISIBLE int
return lws_client_connect_2(wsi);
}
-
+#ifdef LWS_WITH_HTTP_PROXY
static hubbub_error
html_parser_cb(const hubbub_token *token, void *pw)
{
return HUBBUB_OK;
}
-
+#endif
/**
* lws_client_connect_via_info() - Connect to another websocket server
* @i:pointer to lws_client_connect_info struct
wsi->sibling_list = i->parent_wsi->child_list;
i->parent_wsi->child_list = wsi;
}
-
+#ifdef LWS_WITH_HTTP_PROXY
if (i->uri_replace_to)
wsi->rw = lws_rewrite_create(wsi, html_parser_cb,
i->uri_replace_from,
i->uri_replace_to);
+#endif
return wsi;
* transaction if possible
*/
-LWS_VISIBLE int LWS_WARN_UNUSED_RESULT
+int LWS_WARN_UNUSED_RESULT
lws_http_transaction_completed_client(struct lws *wsi)
{
lwsl_debug("%s: wsi %p\n", __func__, wsi);
goto bail2;
}
-#ifndef LWS_NO_CLIENT
+#ifdef LWS_WITH_HTTP_PROXY
wsi->perform_rewrite = 0;
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
if (!strncmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE),
wsi, LWS_CALLBACK_CGI_STDIN_DATA,
wsi->user_space,
(void *)&args, 0);
- if (n < 0)
+ if ((int)n < 0)
goto bail;
} else {
#endif
lwsl_info("%s: real just_kill_connection: %p (sockfd %d)\n", __func__,
wsi, wsi->sock);
-
+#ifdef LWS_WITH_HTTP_PROXY
if (wsi->rw) {
lws_rewrite_destroy(wsi->rw);
wsi->rw = NULL;
}
-
+#endif
/*
* we won't be servicing or receiving anything further from this guy
* delete socket from the internal poll list if still present
}
LWS_VISIBLE LWS_EXTERN int
+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) {
+ if ((*in >= 'A' && *in <= 'Z') ||
+ (*in >= 'a' && *in <= 'z') ||
+ (*in >= '0' && *in <= '9') ||
+ *in == '-' ||
+ *in == '_' ||
+ *in == '.' ||
+ *in == '~')
+ *out++ = *in++;
+ else {
+ *out++ = '%';
+ *out++ = hex[(*in) >> 4];
+ *out++ = hex[(*in++) & 15];
+ }
+ }
+ *out = '\0';
+
+ if (out >= end - 4)
+ return -1;
+
+ return out - start;
+}
+
+LWS_VISIBLE LWS_EXTERN int
lws_is_cgi(struct lws *wsi) {
#ifdef LWS_WITH_CGI
return !!wsi->cgi;
*/
LWS_VISIBLE LWS_EXTERN int
-lws_cgi(struct lws *wsi, char * const *exec_array, int timeout_secs)
+lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len,
+ int timeout_secs)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
- char *env_array[30], cgi_path[400];
+ char *env_array[30], cgi_path[400], e[1024], *p = e,
+ *end = p + sizeof(e) - 1, tok[256];
struct lws_cgi *cgi;
- int n;
+ int n, m, i;
/*
* give the master wsi a cgi struct
/* prepare his CGI env */
n = 0;
+
+ if (lws_is_ssl(wsi))
+ env_array[n++] = "HTTPS=ON";
if (wsi->u.hdr.ah) {
- snprintf(cgi_path, sizeof(cgi_path) - 1, "PATH_INFO=%s",
+ snprintf(cgi_path, sizeof(cgi_path) - 1, "REQUEST_URI=%s",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI));
cgi_path[sizeof(cgi_path) - 1] = '\0';
env_array[n++] = cgi_path;
env_array[n++] = "REQUEST_METHOD=POST";
else
env_array[n++] = "REQUEST_METHOD=GET";
+
+ env_array[n++] = p;
+ p += snprintf(p, end - p, "QUERY_STRING=");
+ /* dump the individual URI Arg parameters */
+ m = 0;
+ while (1) {
+ i = lws_hdr_copy_fragment(wsi, tok, sizeof(tok),
+ WSI_TOKEN_HTTP_URI_ARGS, m);
+ if (i < 0)
+ break;
+ i = lws_urlencode(tok, i, p, end - p);
+ p += i;
+ *p++ = '&';
+ m++;
+ }
+ if (m)
+ p--;
+ *p++ = '\0';
+
+ env_array[n++] = p;
+ p += snprintf(p, end - p, "PATH_INFO=%s",
+ lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI) +
+ script_uri_path_len);
+ p++;
}
- if (lws_is_ssl(wsi))
- env_array[n++] = "HTTPS=ON";
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) {
+ env_array[n++] = p;
+ p += snprintf(p, end - p, "HTTP_REFERER=%s",
+ lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_REFERER));
+ p++;
+ }
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
+ env_array[n++] = p;
+ p += snprintf(p, end - p, "HTTP_HOST=%s",
+ lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
+ p++;
+ }
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) {
+ env_array[n++] = p;
+ p += snprintf(p, end - p, "USER_AGENT=%s",
+ lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT));
+ p++;
+ }
+ env_array[n++] = p;
+ p += snprintf(p, end - p, "SCRIPT_PATH=%s", exec_array[2]) + 1;
+
env_array[n++] = "SERVER_SOFTWARE=libwebsockets";
- env_array[n++] = "PATH=/bin:/usr/bin:/usrlocal/bin";
+ env_array[n++] = "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin";
env_array[n] = NULL;
+#if 0
+ for (m = 0; m < n; m++)
+ lwsl_err(" %s\n", env_array[m]);
+#endif
+
/* we are ready with the redirection pipes... run the thing */
-#ifdef LWS_HAVE_VFORK
- cgi->pid = vfork();
-#else
+#if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)
cgi->pid = fork();
+#else
+ cgi->pid = vfork();
#endif
if (cgi->pid < 0) {
lwsl_err("fork failed, errno %d", errno);
close(cgi->pipe_fds[n][!(n == 0)]);
}
+#if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)
+ for (m = 0; m < n; m++) {
+ p = strchr(env_array[m], '=');
+ *p++ = '\0';
+ setenv(env_array[m], p, 1);
+ }
+ execvp(exec_array[0], &exec_array[0]);
+#else
execvpe(exec_array[0], &exec_array[0], &env_array[0]);
+#endif
+
exit(1);
bail3:
n = 0;
}
if (n) {
- lwsl_err("-- %c\n", c);
+ //lwsl_err("-- %c\n", c);
switch (wsi->hdr_state) {
case LCHS_HEADER:
*p++ = c;
if (!wsi->cgi)
return 0;
- lwsl_notice("%s: wsi %p\n", __func__, wsi);
+// lwsl_notice("%s: wsi %p\n", __func__, wsi);
assert(wsi->cgi);
};
LWS_VISIBLE LWS_EXTERN int
-lws_cgi(struct lws *wsi, char * const *exec_array, int timeout_secs);
+lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len,
+ int timeout_secs);
LWS_VISIBLE LWS_EXTERN int
lws_cgi_write_split_stdout_headers(struct lws *wsi);
BIO *client_bio;
struct lws *pending_read_list_prev, *pending_read_list_next;
#endif
-#ifndef LWS_NO_CLIENT
+#ifdef LWS_WITH_HTTP_PROXY
struct lws_rewrite *rw;
#endif
#ifdef LWS_LATENCY
unsigned int do_ws:1; /* whether we are doing http or ws flow */
unsigned int chunked:1; /* if the clientside connection is chunked */
unsigned int client_rx_avail:1;
+#endif
+#ifdef LWS_WITH_HTTP_PROXY
unsigned int perform_rewrite:1;
#endif
#ifndef LWS_NO_EXTENSIONS
return strncmp((const char *)s->ptr, p, len);
}
typedef hubbub_error (*hubbub_callback_t)(const hubbub_token *token, void *pw);
-LWS_EXTERN int lws_client_socket_service(struct lws_context *context,
- struct lws *wsi,
- struct lws_pollfd *pollfd);
LWS_EXTERN struct lws_rewrite *
lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from, const char *to);
LWS_EXTERN void
#endif
#ifndef LWS_NO_CLIENT
+LWS_EXTERN int lws_client_socket_service(struct lws_context *context,
+ struct lws *wsi,
+ struct lws_pollfd *pollfd);
+LWS_EXTERN int LWS_WARN_UNUSED_RESULT
+lws_http_transaction_completed_client(struct lws *wsi);
#ifdef LWS_OPENSSL_SUPPORT
LWS_EXTERN int
lws_context_init_client_ssl(struct lws_context_creation_info *info,
return forced;
}
+#ifndef LWS_NO_CLIENT
-/*
- *
- */
LWS_VISIBLE int
lws_http_client_read(struct lws *wsi, char **buf, int *len)
{
return 0;
if (wsi->u.http.content_remain &&
- wsi->u.http.content_remain < *len)
+ (int)wsi->u.http.content_remain < *len)
n = wsi->u.http.content_remain;
else
n = *len;
wsi->chunk_remaining < n)
n = wsi->chunk_remaining;
+#ifdef LWS_WITH_HTTP_PROXY
/* hubbub */
if (wsi->perform_rewrite)
lws_rewrite_parse(wsi->rw, (unsigned char *)*buf, n);
else
-
+#endif
if (user_callback_handle_rxflow(wsi->protocol->callback,
wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
wsi->user_space, *buf, n))
wsi->user_space, NULL, 0))
return -1;
- if (lws_http_transaction_completed(wsi))
+ if (lws_http_transaction_completed_client(wsi))
return -1;
return 0;
}
+#endif
/**
* lws_service_fd() - Service polled socket with something waiting
}
drain:
+#ifndef LWS_NO_CLIENT
if (wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED) {
/*
wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
wsi->user_space, NULL, 0))
goto close_and_handled;
-
-
}
+#endif
/*
* give any active extensions a chance to munge the buffer
* before parse. We pass in a pointer to an lws_tokens struct
/* Define to 1 if `vfork' works. */
#cmakedefine LWS_HAVE_WORKING_VFORK
+/* Define to 1 if execvpe() exists */
+#cmakedefine LWS_HAVE_EXECVPE
+
/* Define to 1 if you have the <zlib.h> header file. */
#cmakedefine LWS_HAVE_ZLIB_H
if (!strcmp(&file[n - 5], ".html"))
return "text/html";
+ if (!strcmp(&file[n - 4], ".css"))
+ return "text/css";
+
return NULL;
}
void *in, size_t len)
{
struct per_session_data__http *pss =
- (struct per_session_data__http *)user, *pss1;
+ (struct per_session_data__http *)user;
unsigned char buffer[4096 + LWS_PRE];
unsigned long amount, file_len, sent;
char leaf_path[1024];
unsigned char *end;
struct timeval tv;
unsigned char *p;
+#ifndef LWS_NO_CLIENT
+ struct per_session_data__http *pss1;
struct lws *wsi1;
+#endif
char buf[256];
char b64[64];
int n, m;
i.port = 80;
i.ssl_connection = 0;
if (p[10])
- i.path = in + 10;
+ i.path = (char *)in + 10;
else
i.path = rootpath;
i.host = "git.libwebsockets.org";
}
#endif
+#if 1
/* this example server has no concept of directories */
if (strchr((const char *)in + 1, '/')) {
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
goto try_to_reuse;
}
+#endif
#ifdef LWS_WITH_CGI
- if (!strcmp(in, "/cgitest")) {
+ 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, 5);
+ n = lws_cgi(wsi, cmd, 8, 5);
if (n) {
lwsl_err("%s: cgi failed\n");
return -1;
}
/* if not, send a file the easy way */
- strcpy(buf, resource_path);
+ if (!strncmp(in, "/cgit-data/", 11)) {
+ in = (char *)in + 11;
+ strcpy(buf, "/usr/share/cgit");
+ } else
+ strcpy(buf, resource_path);
+
if (strcmp(in, "/")) {
if (*((const char *)in) != '/')
strcat(buf, "/");
- strncat(buf, in, sizeof(buf) - strlen(resource_path));
+ strncat(buf, in, sizeof(buf) - strlen(buf) - 1);
} else /* default file to serve */
strcat(buf, "/test.html");
buf[sizeof(buf) - 1] = '\0';
/* if we returned non-zero from here, we kill the connection */
break;
-#ifndef LWS_WITH_CLIENT
+#ifndef LWS_NO_CLIENT
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
char ctype[64], ctlen = 0;
lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n");
break;
case LWS_CALLBACK_CGI_TERMINATED:
- lwsl_notice("LWS_CALLBACK_CGI_TERMINATED\n");
+ //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");
+ //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);
+ //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);
lws_filefd_type fd;
#ifdef LWS_WITH_CGI
struct lws_cgi_args args;
+#endif
+#if defined(LWS_WITH_CGI) || !defined(LWS_NO_CLIENT)
int reason_bf;
#endif
unsigned int client_finished:1;