Newer
Older
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
#if defined (LWS_WITH_ESP8266)
#undef memcpy
void *memcpy(void *dest, const void *src, size_t n)
{
return ets_memcpy(dest, src, n);
}
#endif
int
lws_context_init_server(struct lws_context_creation_info *info,
Andy Green
committed
{
struct lws *wsi;
Andy Green
committed
/* set up our external listening socket we serve on */
if (info->port == CONTEXT_PORT_NO_LISTEN)
return 0;
vh = vhost->context->vhost_list;
while (vh) {
if (vh->listen_port == info->port) {
if ((!info->iface && !vh->iface) ||
(info->iface && vh->iface &&
!strcmp(info->iface, vh->iface))) {
vhost->listen_port = info->port;
vhost->iface = info->iface;
lwsl_notice(" using listen skt from vhost %s\n",
vh->name);
return 0;
}
}
vh = vh->vhost_next;
}
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
else
#endif
Andy Green
committed
#ifdef LWS_USE_IPV6
Andy Green
committed
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
else
#endif
sockfd = socket(AF_INET, SOCK_STREAM, 0);
#else
#if defined(LWS_WITH_ESP8266)
sockfd = esp8266_create_tcp_listen_socket(vhost);
if (!lws_sockfd_valid(sockfd)) {
#else
sockfd = mbed3_create_tcp_stream_socket();
if (!lws_sockfd_valid(sockfd)) {
Andy Green
committed
lwsl_err("ERROR opening socket\n");
return 1;
}
Andy Green
committed
/*
* allow us to restart even if old sockets in TIME_WAIT
*/
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&opt, sizeof(opt)) < 0) {
compatible_close(sockfd);
#if defined(LWS_USE_IPV6) && defined(IPV6_V6ONLY)
if (LWS_IPV6_ENABLED(vhost)) {
if (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) {
int value = (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE) ? 1 : 0;
if (setsockopt(sockfd, SOL_IPV6, IPV6_V6ONLY,
(const void*)&value, sizeof(value)) < 0) {
compatible_close(sockfd);
return 1;
}
}
}
#endif
#if defined(__linux__) && defined(SO_REUSEPORT) && LWS_MAX_SMP > 1
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
(const void *)&opt, sizeof(opt)) < 0) {
compatible_close(sockfd);
return 1;
}
Andy Green
committed
n = lws_socket_bind(vhost, sockfd, info->port, info->iface);
vhost->listen_port = info->port;
vhost->iface = info->iface;
Andy Green
committed
wsi = lws_zalloc(sizeof(struct lws));
Andy Green
committed
if (wsi == NULL) {
lwsl_err("Out of mem\n");
Andy Green
committed
}
Andy Green
committed
wsi->sock = sockfd;
Andy Green
committed
vhost->context->pt[m].wsi_listening = wsi;
if (insert_wsi_socket_into_fds(vhost->context, wsi))
Andy Green
committed
vhost->context->count_wsi_allocated++;
vhost->lserv_wsi = wsi;
Andy Green
committed
#else
#if defined(LWS_WITH_ESP8266)
esp8266_tcp_stream_bind(wsi->sock, info->port, wsi);
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
#ifdef LWS_USE_UNIX_SOCK
lwsl_notice(" Listening on \"%s\"\n", info->iface);
else
#endif
lwsl_notice(" Listening on port %d\n", info->port);
}
Andy Green
committed
return 0;
bail:
compatible_close(sockfd);
return 1;
Andy Green
committed
}
_lws_server_listen_accept_flow_control(struct lws *twsi, int on)
struct lws_context_per_thread *pt = &twsi->context->pt[(int)twsi->tsi];
struct lws *wsi = pt->wsi_listening;
lwsl_debug("%s: Thr %d: LISTEN wsi %p: state %d\n",
__func__, twsi->tsi, (void *)wsi, on);
if (on)
n = lws_change_pollfd(wsi, 0, LWS_POLLIN);
else
n = lws_change_pollfd(wsi, LWS_POLLIN, 0);
return n;
}
#if defined(LWS_WITH_ESP8266)
#undef strchr
#define strchr ets_strchr
#endif
struct lws_vhost *
lws_select_vhost(struct lws_context *context, int port, const char *servername)
{
struct lws_vhost *vhost = context->vhost_list;
const char *p;
int n, m, colon;
n = strlen(servername);
colon = n;
p = strchr(servername, ':');
if (p)
colon = p - servername;
/* first try exact matches */
!strncmp(vhost->name, servername, colon)) {
lwsl_info("SNI: Found: %s\n", servername);
return vhost;
}
vhost = vhost->vhost_next;
}
/*
* if no exact matches, try matching *.vhost-name
* unintentional matches are possible but resolve to x.com for *.x.com
* which is reasonable. If exact match exists we already chose it and
* never reach here. SSL will still fail it if the cert doesn't allow
* *.x.com.
*/
vhost = context->vhost_list;
while (vhost) {
m = strlen(vhost->name);
if (port == vhost->listen_port &&
m <= (colon - 2) &&
servername[colon - m - 1] == '.' &&
!strncmp(vhost->name, servername + colon - m, m)) {
lwsl_info("SNI: Found %s on wildcard: %s\n",
servername, vhost->name);
return vhost;
}
vhost = vhost->vhost_next;
}
LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name)
{
int n;
for (n = 0; n < vh->count_protocols; n++)
if (!strcmp(name, vh->protocols[n].name))
return &vh->protocols[n];
return NULL;
}
LWS_VISIBLE LWS_EXTERN const char *
lws_get_mimetype(const char *file, const struct lws_http_mount *m)
const struct lws_protocol_vhost_options *pvo = NULL;
if (m)
pvo = m->extra_mimetypes;
if (n < 5)
return NULL;
if (!strcmp(&file[n - 4], ".ico"))
return "image/x-icon";
if (!strcmp(&file[n - 4], ".gif"))
return "image/gif";
if (!strcmp(&file[n - 3], ".js"))
return "text/javascript";
if (!strcmp(&file[n - 4], ".png"))
return "image/png";
if (!strcmp(&file[n - 3], ".gz"))
return "application/gzip";
if (!strcmp(&file[n - 4], ".JPG"))
return "image/jpeg";
if (!strcmp(&file[n - 5], ".html"))
return "text/html";
if (!strcmp(&file[n - 4], ".css"))
return "text/css";
if (!strcmp(&file[n - 4], ".txt"))
return "text/plain";
if (!strcmp(&file[n - 4], ".ttf"))
return "application/x-font-ttf";
if (!strcmp(&file[n - 5], ".woff"))
return "application/font-woff";
if (!strcmp(&file[n - 4], ".xml"))
return "application/xml";
while (pvo) {
if (!strcmp(&file[n - strlen(pvo->name)], pvo->name))
return pvo->value;
pvo = pvo->next;
}
static int
lws_http_serve(struct lws *wsi, char *uri, const char *origin,
const struct lws_http_mount *m)
const struct lws_protocol_vhost_options *pvo = m->interpret;
struct lws_process_html_args args;
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266)
OndraCo
committed
#endif
unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266)
goto bail;
}
lwsl_debug(" %s mode %d\n", path, S_IFMT & st.st_mode);
len = readlink(path, sym, sizeof(sym) - 1);
if (len) {
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);
n = sprintf(sym, "%08lX%08lX", (unsigned long)st.st_size,
(unsigned long)st.st_mtime);
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH)) {
/*
* he thinks he has some version of it already,
* check if the tag matches
*/
if (!strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH))) {
lwsl_debug("%s: ETAG match %s %s\n", __func__,
uri, origin);
/* we don't need to send the payload */
if (lws_add_http_header_status(wsi, 304, &p, end))
return -1;
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_ETAG,
(unsigned char *)sym, n, &p, end))
return -1;
if (lws_finalize_http_header(wsi, &p, end))
return -1;
n = lws_write(wsi, start, p - start,
if (n != (p - start)) {
lwsl_err("_write returned %d from %d\n", n, p - start);
return -1;
}
return lws_http_transaction_completed(wsi);
}
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,
(unsigned char *)sym, n, &p, end))
return -1;
OndraCo
committed
#endif
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
wsi->sending_chunked = 0;
/*
* check if this is in the list of file suffixes to be interpreted by
* a protocol
*/
while (pvo) {
n = strlen(path);
if (n > (int)strlen(pvo->name) &&
!strcmp(&path[n - strlen(pvo->name)], pvo->name)) {
wsi->sending_chunked = 1;
wsi->protocol_interpret_idx = (char)(long)pvo->value;
lwsl_info("want %s interpreted by %s\n", path,
wsi->vhost->protocols[(int)(long)(pvo->value)].name);
wsi->protocol = &wsi->vhost->protocols[(int)(long)(pvo->value)];
if (lws_ensure_user_space(wsi))
return -1;
break;
}
pvo = pvo->next;
}
if (m->protocol) {
const struct lws_protocols *pp = lws_vhost_name_to_protocol(
wsi->vhost, m->protocol);
args.p = (char *)p;
args.max_len = end - p;
if (pp->callback(wsi, LWS_CALLBACK_ADD_HEADERS,
wsi->user_space, &args, 0))
return -1;
p = (unsigned char *)args.p;
}
n = lws_serve_http_file(wsi, path, mimetype, (char *)start, p - start);
if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
return -1; /* error or can't reuse connection: close the socket */
return 0;
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
const struct lws_http_mount *
lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)
{
const struct lws_http_mount *hm, *hit = NULL;
int best = 0;
hm = wsi->vhost->mount_list;
while (hm) {
if (uri_len >= 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->origin_protocol == LWSMPRO_CALLBACK ||
((hm->origin_protocol == LWSMPRO_CGI ||
lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||
hm->protocol) &&
hm->mountpoint_len > best)) {
best = hm->mountpoint_len;
hit = hm;
}
}
hm = hm->mount_next;
}
return hit;
}
int
lws_http_action(struct lws *wsi)
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
enum http_connection_type connection_type;
char content_length_str[32];
char http_version_str[10];
char http_conn_str[20];
static const unsigned char methods[] = {
WSI_TOKEN_GET_URI,
WSI_TOKEN_POST_URI,
WSI_TOKEN_OPTIONS_URI,
WSI_TOKEN_PUT_URI,
WSI_TOKEN_PATCH_URI,
WSI_TOKEN_DELETE_URI,
#if defined(_DEBUG) || defined(LWS_WITH_ACCESS_LOG)
static const char * const method_names[] = {
"GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE",
#ifdef LWS_USE_HTTP2
":path",
#endif
};
static const char * const oprot[] = {
"http://", "https://"
};
/* it's not websocket.... shall we accept it as http? */
for (n = 0; n < ARRAY_SIZE(methods); n++)
if (lws_hdr_total_length(wsi, methods[n]))
count++;
if (!count) {
lwsl_warn("Missing URI in HTTP request\n");
goto bail_nuke_ah;
}
if (count != 1) {
lwsl_warn("multiple methods?\n");
if (lws_ensure_user_space(wsi))
for (n = 0; n < ARRAY_SIZE(methods); n++)
if (lws_hdr_total_length(wsi, methods[n])) {
uri_ptr = lws_hdr_simple_ptr(wsi, methods[n]);
uri_len = lws_hdr_total_length(wsi, methods[n]);
lwsl_info("Method: %s request for '%s'\n",
method_names[n], uri_ptr);
/* we insist on absolute paths */
if (uri_ptr[0] != '/') {
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
goto bail_nuke_ah;
}
/* HTTP header had a content length? */
wsi->u.http.content_length = 0;
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||
lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))
wsi->u.http.content_length = 100 * 1024 * 1024;
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
lws_hdr_copy(wsi, content_length_str,
sizeof(content_length_str) - 1,
WSI_TOKEN_HTTP_CONTENT_LENGTH);
wsi->u.http.content_length = atoi(content_length_str);
}
if (wsi->http2_substream) {
wsi->u.http.request_version = HTTP_VERSION_2;
} else {
/* http_version? Default to 1.0, override with token: */
request_version = HTTP_VERSION_1_0;
/* Works for single digit HTTP versions. : */
http_version_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP);
if (http_version_len > 7) {
lws_hdr_copy(wsi, http_version_str,
sizeof(http_version_str) - 1, WSI_TOKEN_HTTP);
if (http_version_str[5] == '1' && http_version_str[7] == '1')
request_version = HTTP_VERSION_1_1;
}
wsi->u.http.request_version = request_version;
/* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */
if (request_version == HTTP_VERSION_1_1)
connection_type = HTTP_CONNECTION_KEEP_ALIVE;
else
connection_type = HTTP_CONNECTION_CLOSE;
/* Override default if http "Connection:" header: */
if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1,
WSI_TOKEN_CONNECTION);
http_conn_str[sizeof(http_conn_str) - 1] = '\0';
if (!strcasecmp(http_conn_str, "keep-alive"))
connection_type = HTTP_CONNECTION_KEEP_ALIVE;
else
if (!strcasecmp(http_conn_str, "close"))
connection_type = HTTP_CONNECTION_CLOSE;
}
wsi->u.http.connection_type = connection_type;
n = wsi->protocol->callback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,
* if there is content supposed to be coming,
* put a timeout on it having arrived
#ifdef LWS_OPENSSL_SUPPORT
* we accepted http:// only so we could redirect to
* https://, so issue the redirect. Create the redirection
* URI from the host: header and ignore the path part
*/
unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
*end = p + 512;
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
goto bail_nuke_ah;
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
end, n, &p, end);
goto bail_nuke_ah;
return lws_http_transaction_completed(wsi);
}
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
#ifdef LWS_WITH_ACCESS_LOG
/*
* Produce Apache-compatible log string for wsi, like this:
*
* 2.31.234.19 - - [27/Mar/2016:03:22:44 +0800]
* "GET /aep-screen.png HTTP/1.1"
* 200 152987 "https://libwebsockets.org/index.html"
* "Mozilla/5.0 (Macint... Chrome/49.0.2623.87 Safari/537.36"
*
*/
{
static const char * const hver[] = {
"http/1.0", "http/1.1", "http/2"
};
#ifdef LWS_USE_IPV6
char ads[INET6_ADDRSTRLEN];
#else
char ads[INET_ADDRSTRLEN];
#endif
char da[64];
const char *pa, *me;
struct tm *tmp;
time_t t = time(NULL);
int l = 256;
if (wsi->access_log_pending)
lws_access_log(wsi);
wsi->access_log.header_log = lws_malloc(l);
tmp = localtime(&t);
if (tmp)
strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", tmp);
else
strcpy(da, "01/Jan/1970:00:00:00 +0000");
pa = lws_get_peer_simple(wsi, ads, sizeof(ads));
if (!pa)
pa = "(unknown)";
if (meth >= 0)
me = method_names[meth];
else
me = "unknown";
snprintf(wsi->access_log.header_log, l,
"%s - - [%s] \"%s %s %s\"",
pa, da, me, uri_ptr,
hver[wsi->u.http.request_version]);
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
if (l) {
wsi->access_log.user_agent = lws_malloc(l + 2);
if (wsi->access_log.user_agent)
lws_hdr_copy(wsi, wsi->access_log.user_agent,
l + 1, WSI_TOKEN_HTTP_USER_AGENT);
else
lwsl_err("OOM getting user agent\n");
}
wsi->access_log_pending = 1;
hit = lws_find_mount(wsi, uri_ptr, uri_len);
if (!hit) {
/* deferred cleanup and reset to protocols[0] */
if (lws_bind_protocol(wsi, &wsi->vhost->protocols[0]))
return 1;
n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
wsi->user_space, uri_ptr, uri_len);
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
args.p = uri_ptr;
args.len = uri_len;
args.max_len = hit->auth_mask;
args.final = 0; /* used to signal callback dealt with it */
n = wsi->protocol->callback(wsi, LWS_CALLBACK_CHECK_ACCESS_RIGHTS,
wsi->user_space, &args, 0);
if (n) {
lws_return_http_status(wsi, HTTP_STATUS_UNAUTHORIZED,
NULL);
goto bail_nuke_ah;
}
if (args.final) /* callback completely handled it well */
return 0;
/*
* if we have a mountpoint like https://xxx.com/yyy
* there is an implied / at the end for our purposes since
* we can only mount on a "directory".
*
* But if we just go with that, the browser cannot understand
* that he is actually looking down one "directory level", so
* even though we give him /yyy/abc.html he acts like the
* current directory level is /. So relative urls like "x.png"
* wrongly look outside the mountpoint.
*
* Therefore if we didn't come in on a url with an explicit
* / 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 == LWSMPRO_REDIR_HTTP ||
hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
(*s != '/' ||
(hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
(hit->origin_protocol != LWSMPRO_CGI &&
hit->origin_protocol != LWSMPRO_CALLBACK //&&
//hit->protocol == NULL
)) {
unsigned char *start = pt->serv_buf + LWS_PRE,
*p = start, *end = p + 512;
lwsl_debug("Doing 301 '%s' org %s\n", s, hit->origin);
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST))
/* > at start indicates deal with by redirect */
if (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
hit->origin_protocol == LWSMPRO_REDIR_HTTPS)
n = snprintf((char *)end, 256, "%s%s",
oprot[hit->origin_protocol & 1],
hit->origin);
else
n = snprintf((char *)end, 256,
"%s%s%s/", oprot[lws_is_ssl(wsi)],
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
uri_ptr);
n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
end, n, &p, end);
if ((int)n < 0)
goto bail_nuke_ah;
return lws_http_transaction_completed(wsi);
}
/*
* A particular protocol callback is mounted here?
*
* For the duration of this http transaction, bind us to the
* associated protocol
*/
if (hit->origin_protocol == LWSMPRO_CALLBACK || hit->protocol) {
const struct lws_protocols *pp;
const char *name = hit->origin;
if (hit->protocol)
name = hit->protocol;
pp = lws_vhost_name_to_protocol(wsi->vhost, name);
if (!pp) {
n = -1;
lwsl_err("Unable to find plugin '%s'\n",
hit->origin);
return 1;
if (hit->cgienv && wsi->protocol->callback(wsi,
LWS_CALLBACK_HTTP_PMO,
wsi->user_space, (void *)hit->cgienv, 0))
return 1;
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
wsi->user_space,
uri_ptr + hit->mountpoint_len,
uri_len - hit->mountpoint_len);
/* 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 = 5;
if (hit->cgi_timeout)
n = hit->cgi_timeout;
n = lws_cgi(wsi, cmd, hit->mountpoint_len, n,
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);
n = strlen(s);
if (s[0] == '\0' || (n == 1 && s[n - 1] == '/'))
s = (char *)hit->def;
if (!s)
s = "index.html";
wsi->cache_secs = hit->cache_max_age;
wsi->cache_reuse = hit->cache_reusable;
wsi->cache_revalidate = hit->cache_revalidate;
wsi->cache_intermediaries = hit->cache_intermediaries;
n = lws_http_serve(wsi, s, hit->origin, hit);
if (n) {
/*
* lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
*/
if (hit->protocol) {
const struct lws_protocols *pp = lws_vhost_name_to_protocol(
wsi->vhost, hit->protocol);
n = pp->callback(wsi, LWS_CALLBACK_HTTP,
wsi->user_space,
uri_ptr + hit->mountpoint_len,
uri_len - hit->mountpoint_len);
} else
n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
if (n) {
lwsl_info("LWS_CALLBACK_HTTP closing\n");
return 1;
}
* If we're not issuing a file, check for content_length or
* HTTP keep-alive. No keep-alive header allocation for
* ISSUING_FILE, as this uses HTTP/1.0.
*
* In any case, return 0 and let lws_read decide how to
/* Prepare to read body if we have a content length: */
if (wsi->u.http.content_length > 0)
/* we're closing, losing some rx is OK */
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
int
lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p)
{
// if (wsi->protocol == p)
// return 0;
if (wsi->protocol)
wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_DROP_PROTOCOL,
wsi->user_space, NULL, 0);
if (!wsi->user_space_externally_allocated)
lws_free_set_NULL(wsi->user_space);
wsi->protocol = p;
if (!p)
return 0;
if (lws_ensure_user_space(wsi))
return 1;
if (wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_BIND_PROTOCOL,
wsi->user_space, NULL, 0))
return 1;
return 0;
}
int
lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)