Newer
Older
/*
* libwebsockets - small server side websockets and web server implementation
*
*
* 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"
"GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", "CONNECT", "HEAD",
/*
* return 0: all done
* 1: nonfatal error
* <0: fatal error
*/
int
lws_context_init_server(struct lws_context_creation_info *info,
Andy Green
committed
{
#if defined(__linux__) && defined(SO_REUSEPORT)
int n1;
struct lws *wsi;
int m = 0, is;
Andy Green
committed
if (info) {
vhost->iface = info->iface;
vhost->listen_port = info->port;
}
Andy Green
committed
/* set up our external listening socket we serve on */
if (vhost->listen_port == CONTEXT_PORT_NO_LISTEN ||
vhost->listen_port == CONTEXT_PORT_NO_LISTEN_SERVER)
Andy Green
committed
return 0;
if (vh->listen_port == vhost->listen_port) {
if (((!vhost->iface && !vh->iface) ||
(vhost->iface && vh->iface &&
!strcmp(vhost->iface, vh->iface))) &&
vh->lserv_wsi
) {
lwsl_notice(" using listen skt from vhost %s\n",
vh->name);
return 0;
}
}
vh = vh->vhost_next;
}
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
if (vhost->iface) {
/*
* let's check before we do anything else about the disposition
* of the interface he wants to bind to...
*/
is = lws_socket_bind(vhost, LWS_SOCK_INVALID, vhost->listen_port, vhost->iface);
lwsl_debug("initial if check says %d\n", is);
deal:
lws_context_lock(vhost->context);
lws_start_foreach_llp(struct lws_vhost **, pv,
vhost->context->no_listener_vhost_list) {
if (is >= LWS_ITOSA_USABLE && *pv == vhost) {
/* on the list and shouldn't be: remove it */
lwsl_debug("deferred iface: removing vh %s\n", (*pv)->name);
*pv = vhost->no_listener_vhost_list;
vhost->no_listener_vhost_list = NULL;
goto done_list;
}
if (is < LWS_ITOSA_USABLE && *pv == vhost)
goto done_list;
} lws_end_foreach_llp(pv, no_listener_vhost_list);
/* not on the list... */
if (is < LWS_ITOSA_USABLE) {
/* ... but needs to be: so add it */
lwsl_debug("deferred iface: adding vh %s\n", vhost->name);
vhost->no_listener_vhost_list = vhost->context->no_listener_vhost_list;
vhost->context->no_listener_vhost_list = vhost;
}
done_list:
lws_context_unlock(vhost->context);
switch (is) {
default:
break;
case LWS_ITOSA_NOT_EXIST:
/* can't add it */
if (info) /* first time */
lwsl_err("VH %s: iface %s port %d DOESN'T EXIST\n",
vhost->name, vhost->iface, vhost->listen_port);
return 1;
case LWS_ITOSA_NOT_USABLE:
/* can't add it */
if (info) /* first time */
lwsl_err("VH %s: iface %s port %d NOT USABLE\n",
vhost->name, vhost->iface, vhost->listen_port);
return 1;
}
}
if (LWS_UNIX_SOCK_ENABLED(vhost))
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
else
if (LWS_IPV6_ENABLED(vhost))
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
else
Andy Green
committed
#endif
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == LWS_SOCK_INVALID) {
lwsl_err("ERROR opening socket\n");
return 1;
}
#if (defined(WIN32) || defined(_WIN32)) && defined(SO_EXCLUSIVEADDRUSE)
/*
* only accept that we are the only listener on the port
* https://msdn.microsoft.com/zh-tw/library/
* windows/desktop/ms740621(v=vs.85).aspx
*
* for lws, to match Linux, we default to exclusive listen
*/
if (!lws_check_opt(vhost->options,
LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE)) {
if (setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
(const void *)&opt, sizeof(opt)) < 0) {
lwsl_err("reuseaddr failed\n");
compatible_close(sockfd);
}
} else
#endif
/*
* allow us to restart even if old sockets in TIME_WAIT
*/
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&opt, sizeof(opt)) < 0) {
lwsl_err("reuseaddr failed\n");
compatible_close(sockfd);
#if defined(LWS_WITH_IPV6) && defined(IPV6_V6ONLY)
if (LWS_IPV6_ENABLED(vhost) &&
vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) {
int value = (vhost->options &
LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE) ? 1 : 0;
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
(const void*)&value, sizeof(value)) < 0) {
compatible_close(sockfd);
#if defined(__linux__) && defined(SO_REUSEPORT)
n1 = lws_check_opt(vhost->options,
LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE);
/* keep coverity happy */
#else
n = n1;
if (n && vhost->context->count_threads > 1)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
(const void *)&opt, sizeof(opt)) < 0) {
compatible_close(sockfd);
lws_plat_set_socket_options(vhost, sockfd);
Andy Green
committed
is = lws_socket_bind(vhost, sockfd, vhost->listen_port, vhost->iface);
/*
* There is a race where the network device may come up and then
* go away and fail here. So correctly handle unexpected failure
* here despite we earlier confirmed it.
*/
if (is < 0) {
lwsl_info("%s: lws_socket_bind says %d\n", __func__, is);
compatible_close(sockfd);
goto deal;
}
vhost->listen_port = is;
lwsl_debug("%s: lws_socket_bind says %d\n", __func__, is);
Andy Green
committed
wsi = lws_zalloc(sizeof(struct lws), "listen wsi");
if (wsi == NULL) {
lwsl_err("Out of mem\n");
goto bail;
}
wsi->context = vhost->context;
wsi->desc.sockfd = sockfd;
lws_role_transition(wsi, 0, LRS_UNCONNECTED, &role_ops_listen);
wsi->protocol = vhost->protocols;
wsi->tsi = m;
wsi->vhost = vhost;
wsi->listener = 1;
Andy Green
committed
if (LWS_LIBUV_ENABLED(vhost->context))
lws_uv_initvhost(vhost, wsi);
if (__insert_wsi_socket_into_fds(vhost->context, wsi)) {
lwsl_notice("inserting wsi socket into fds failed\n");
Andy Green
committed
vhost->context->count_wsi_allocated++;
vhost->lserv_wsi = wsi;
Andy Green
committed
n = listen(wsi->desc.sockfd, LWS_SOMAXCONN);
if (n < 0) {
lwsl_err("listen failed with error %d\n", LWS_ERRNO);
vhost->lserv_wsi = NULL;
vhost->context->count_wsi_allocated--;
__remove_wsi_socket_from_fds(wsi);
goto bail;
}
if (!lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
lwsl_info(" Listening on \"%s\"\n", vhost->iface);
lwsl_info(" Listening on port %d\n", vhost->listen_port);
Andy Green
committed
return 0;
Andy Green
committed
}
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 = (int)strlen(servername);
colon = n;
p = strchr(servername, ':');
if (p)
colon = lws_ptr_diff(p, servername);
/* Priotity 1: first try exact matches */
!strncmp(vhost->name, servername, colon)) {
lwsl_info("SNI: Found: %s\n", servername);
return vhost;
}
vhost = vhost->vhost_next;
}
* Priority 2: 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 = (int)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;
}
/* Priority 3: match the first vhost on our port */
vhost = context->vhost_list;
while (vhost) {
if (port == vhost->listen_port) {
lwsl_info("vhost match to %s based on port %d\n",
vhost->name, port);
return vhost;
}
vhost = vhost->vhost_next;
}
/* no match */
LWS_VISIBLE LWS_EXTERN const char *
lws_get_mimetype(const char *file, const struct lws_http_mount *m)
int n = (int)strlen(file);
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], ".svg"))
return "image/svg+xml";
if (!strcmp(&file[n - 4], ".ttf"))
return "application/x-font-ttf";
if (!strcmp(&file[n - 4], ".otf"))
return "application/font-woff";
if (!strcmp(&file[n - 5], ".woff"))
return "application/font-woff";
if (!strcmp(&file[n - 4], ".xml"))
return "application/xml";
if (pvo->name[0] == '*') /* ie, match anything */
return pvo->value;
if (!strcmp(&file[n - strlen(pvo->name)], pvo->name))
return pvo->value;
pvo = pvo->next;
}
static lws_fop_flags_t
lws_vfs_prepare_flags(struct lws *wsi)
{
lws_fop_flags_t f = 0;
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING))
return f;
if (strstr(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING),
"gzip")) {
lwsl_info("client indicates GZIP is acceptable\n");
f |= LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP;
}
return f;
}
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) && defined(LWS_HAVE__STAT32I64)
struct _stat32i64 st;
#else
OndraCo
committed
#endif
unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
if (!wsi->vhost)
return -1;
if (wsi->vhost->error_document_404 &&
!strcmp(uri, wsi->vhost->error_document_404))
wsi->handling_404 = 1;
fflags |= lws_vfs_prepare_flags(wsi);
if (wsi->http.fop_fd)
lws_vfs_file_close(&wsi->http.fop_fd);
wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->context->fops,
lwsl_info("Unable to open '%s': errno %d\n", path, errno);
/* if it can't be statted, don't try */
if (fflags & LWS_FOP_FLAG_VIRTUAL)
break;
#if defined(LWS_WITH_ESP32)
break;
#endif
#else
#if defined(LWS_HAVE__STAT32I64)
if (_stat32i64(path, &st)) {
lwsl_info("unable to stat %s\n", path);
goto bail;
}
#else
if (stat(path, &st)) {
lwsl_info("unable to stat %s\n", path);
goto bail;
}
wsi->http.fop_fd->mod_time = (uint32_t)st.st_mtime;
len = readlink(path, sym, sizeof(sym) - 1);
if (len) {
lwsl_err("Failed to read link %s\n", path);
goto bail;
}
if ((S_IFMT & st.st_mode) == S_IFDIR) {
lwsl_debug("default filename append to dir\n");
origin, uri);
}
} while ((S_IFMT & st.st_mode) != S_IFREG && spin < 5);
(unsigned long long)lws_vfs_get_length(wsi->http.fop_fd),
(unsigned long)lws_vfs_get_mod_time(wsi->http.fop_fd));
/* disable ranges if IF_RANGE token invalid */
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_RANGE))
if (strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_RANGE)))
/* differs - defeat Range: */
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);
if (lws_add_http_header_status(wsi,
HTTP_STATUS_NOT_MODIFIED, &p, end))
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,
Martin Milata
committed
lwsl_err("_write returned %d from %ld\n", n,
(long)(p - start));
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,
(unsigned char *)sym, n, &p, end))
return -1;
OndraCo
committed
#endif
if (!mimetype[0])
lwsl_debug("sending no mimetype for %s\n", path);
wsi->sending_chunked = 0;
/*
* check if this is in the list of file suffixes to be interpreted by
* a protocol
*/
while (pvo) {
n = (int)strlen(path);
if (n > (int)strlen(pvo->name) &&
!strcmp(&path[n - strlen(pvo->name)], pvo->name)) {
wsi->interpreting = 1;
if (!wsi->http2_substream)
wsi->sending_chunked = 1;
wsi->protocol_interpret_idx =
(char)(lws_intptr_t)pvo->value;
wsi->vhost->protocols[
(int)(lws_intptr_t)(pvo->value)].name);
wsi->protocol = &wsi->vhost->protocols[
(int)(lws_intptr_t)(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(
args.max_len = lws_ptr_diff(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,
lws_ptr_diff(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;
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) ||
lws_hdr_total_length(wsi,
WSI_TOKEN_HTTP_COLON_PATH)) ||
hm->protocol) &&
hm->mountpoint_len > best)) {
best = hm->mountpoint_len;
hit = hm;
}
}
hm = hm->mount_next;
}
return hit;
}
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
static int
lws_find_string_in_file(const char *filename, const char *string, int stringlen)
{
char buf[128];
int fd, match = 0, pos = 0, n = 0, hit = 0;
fd = open(filename, O_RDONLY);
if (fd < 0) {
lwsl_err("can't open auth file: %s\n", filename);
return 1;
}
while (1) {
if (pos == n) {
n = read(fd, buf, sizeof(buf));
if (n <= 0) {
if (match == stringlen)
hit = 1;
break;
}
pos = 0;
}
if (match == stringlen) {
if (buf[pos] == '\r' || buf[pos] == '\n') {
hit = 1;
break;
}
match = 0;
}
if (buf[pos] == string[match])
match++;
else
match = 0;
pos++;
}
close(fd);
return hit;
}
static int
lws_unauthorised_basic_auth(struct lws *wsi)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
unsigned char *start = pt->serv_buf + LWS_PRE,
*p = start, *end = p + 512;
char buf[64];
int n;
/* no auth... tell him it is required */
if (lws_add_http_header_status(wsi, HTTP_STATUS_UNAUTHORIZED, &p, end))
return -1;
n = lws_snprintf(buf, sizeof(buf), "Basic realm=\"lwsws\"");
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
(unsigned char *)buf, n, &p, end))
return -1;
if (lws_finalize_http_header(wsi, &p, end))
return -1;
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS |
LWS_WRITE_H2_STREAM_END);
if (n < 0)
return -1;
return lws_http_transaction_completed(wsi);
}
if (p[0] == 'h' && p[1] == 't' && p[2] == 't' && p[3] == 'p') {
p += 4;
if (*p == 's')
p++;
if (*p == ':') {
p++;
if (*p == '/')
p++;
}
}
while (*p) {
if (p[0] == '/' && p[1] == '/') {
char *p1 = p;
while (*p1) {
*p1 = p1[1];
p1++;
}
continue;
}
p++;
}
return 0;
}
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,
WSI_TOKEN_CONNECT,
WSI_TOKEN_HTTP_COLON_PATH,
#endif
};
static int
lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)
{
int n, count = 0;
for (n = 0; n < (int)ARRAY_SIZE(methods); n++)
if (lws_hdr_total_length(wsi, methods[n]))
count++;
if (!count) {
lwsl_warn("Missing URI in HTTP request\n");
if (count != 1 &&
!(wsi->http2_substream &&
lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH))) {
for (n = 0; n < (int)ARRAY_SIZE(methods); n++)
if (lws_hdr_total_length(wsi, methods[n])) {
*puri_ptr = lws_hdr_simple_ptr(wsi, methods[n]);
*puri_len = lws_hdr_total_length(wsi, methods[n]);
return n;
return -1;
}
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;
enum http_version request_version;
char content_length_str[32];
struct lws_process_html_args args;
const struct lws_http_mount *hit = NULL;
unsigned int n;
char http_version_str[10];
char http_conn_str[20];
int http_version_len;
char *uri_ptr = NULL, *s;
int uri_len = 0, meth;
static const char * const oprot[] = {
"http://", "https://"
};
meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
if (meth < 0 || meth >= (int)ARRAY_SIZE(method_names))
/* we insist on absolute paths */
if (!uri_ptr || uri_ptr[0] != '/') {
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
goto bail_nuke_ah;
}
lwsl_info("Method: '%s' (%d), request for '%s'\n", method_names[meth],
meth, uri_ptr);
if (wsi->role_ops && wsi->role_ops->check_upgrades)
switch (wsi->role_ops->check_upgrades(wsi)) {
case LWS_UPG_RET_DONE:
return 0;
case LWS_UPG_RET_CONTINUE:
break;
case LWS_UPG_RET_BAIL:
goto bail_nuke_ah;
if (lws_ensure_user_space(wsi))
goto bail_nuke_ah;
/* HTTP header had a content length? */
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->http.rx_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->http.rx_content_length = atoll(content_length_str);
} 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')
/* 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;
}
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
* 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);
}
lws_prepare_access_log_info(wsi, uri_ptr, meth);
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);