2013-01-18 11:43:21 +08:00
|
|
|
/*
|
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
2013-01-18 11:43:21 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to
|
|
|
|
* deal in the Software without restriction, including without limitation the
|
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2013-01-18 11:43:21 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
2013-01-18 11:43:21 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
* IN THE SOFTWARE.
|
2013-01-18 11:43:21 +08:00
|
|
|
*/
|
|
|
|
|
2019-08-15 10:49:52 +01:00
|
|
|
#include "private-lib-core.h"
|
2013-01-18 11:43:21 +08:00
|
|
|
|
2021-05-25 06:09:01 +01:00
|
|
|
#if !defined(SOL_TCP) && defined(IPPROTO_TCP)
|
|
|
|
#define SOL_TCP IPPROTO_TCP
|
|
|
|
#endif
|
|
|
|
|
2017-10-16 12:52:32 +08:00
|
|
|
const char * const method_names[] = {
|
2020-02-28 10:31:04 +00:00
|
|
|
"GET", "POST",
|
|
|
|
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
|
|
|
|
"OPTIONS", "PUT", "PATCH", "DELETE",
|
|
|
|
#endif
|
|
|
|
"CONNECT", "HEAD",
|
2017-09-28 11:29:03 +08:00
|
|
|
#ifdef LWS_WITH_HTTP2
|
2017-10-13 10:33:02 +08:00
|
|
|
":path",
|
2017-09-06 09:30:32 +08:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2018-08-13 16:49:58 +08:00
|
|
|
static const char * const intermediates[] = { "private", "public" };
|
2019-08-18 10:35:43 +01:00
|
|
|
#endif
|
2018-08-13 16:49:58 +08:00
|
|
|
|
2018-03-29 13:32:33 +08:00
|
|
|
/*
|
|
|
|
* return 0: all done
|
|
|
|
* 1: nonfatal error
|
|
|
|
* <0: fatal error
|
2018-04-26 15:27:02 +08:00
|
|
|
*
|
|
|
|
* REQUIRES CONTEXT LOCK HELD
|
2018-03-29 13:32:33 +08:00
|
|
|
*/
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2021-06-21 10:36:36 +01:00
|
|
|
|
|
|
|
struct vh_sock_args {
|
|
|
|
const struct lws_context_creation_info *info;
|
|
|
|
struct lws_vhost *vhost;
|
|
|
|
int af;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
check_extant(struct lws_dll2 *d, void *user)
|
|
|
|
{
|
|
|
|
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
|
|
|
struct vh_sock_args *a = (struct vh_sock_args *)user;
|
|
|
|
|
|
|
|
if (!lws_vhost_compare_listen(wsi->a.vhost, a->vhost))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (wsi->af != a ->af)
|
|
|
|
return 0;
|
|
|
|
|
2024-01-02 07:15:12 +00:00
|
|
|
if (a->info && a->info->vh_listen_sockfd &&
|
|
|
|
wsi->desc.sockfd != a->info->vh_listen_sockfd)
|
|
|
|
return 0;
|
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
lwsl_notice(" using listen skt from vhost %s\n", wsi->a.vhost->name);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Creates a single listen socket of a specific AF
|
|
|
|
*/
|
|
|
|
|
ah http1.1 deal with pipelined headers properly
Connections must hold an ah for the whole time they are
processing one header set, even if eg, the headers are
fragmented and it involves network roundtrip times.
However on http1.1 / keepalive, it must drop the ah when
there are no more header sets to deal with, and reacquire
the ah later when more data appears. It's because the
time between header sets / http1.1 requests is unbounded
and the ah would be tied up forever.
But in the case that we got pipelined http1.1 requests,
even partial already buffered, we must keep the ah,
resetting it instead of dropping it. Because we store
the rx data conveniently in a per-tsi buffer since it only
does one thing at a time per thread, we cannot go back to
the event loop to await a new ah inside one service action.
But no problem since we definitely already have an ah,
let's just reuse it at http completion time if more rx is
already buffered.
NB: attack.sh makes request with echo | nc, this
accidentally sends a trailing '\n' from the echo showing
this problem. With this patch attack.sh can complete well.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-01-30 11:43:10 +08:00
|
|
|
int
|
2021-06-21 10:36:36 +01:00
|
|
|
_lws_vhost_init_server_af(struct vh_sock_args *a)
|
2014-04-03 08:24:29 +08:00
|
|
|
{
|
2021-06-21 10:36:36 +01:00
|
|
|
struct lws_context *cx = a->vhost->context;
|
2020-08-31 08:12:16 +01:00
|
|
|
struct lws_context_per_thread *pt;
|
2023-12-13 05:22:14 +00:00
|
|
|
int n, opt = 1, limit = 1, san = 2;
|
2015-12-06 08:00:03 +08:00
|
|
|
lws_sockfd_type sockfd;
|
2021-06-21 10:36:36 +01:00
|
|
|
struct lws *wsi;
|
2024-01-15 15:32:56 +00:00
|
|
|
int m = 0, is = 0;
|
2021-05-06 14:33:05 +01:00
|
|
|
#if defined(LWS_WITH_IPV6)
|
2021-06-21 10:36:36 +01:00
|
|
|
int value = 1;
|
2021-05-06 14:33:05 +01:00
|
|
|
#endif
|
2014-04-03 08:24:29 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
(void)method_names;
|
2017-02-18 17:26:40 +08:00
|
|
|
(void)opt;
|
2018-03-29 13:32:33 +08:00
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
lwsl_info("%s: af %d\n", __func__, (int)a->af);
|
2014-04-03 08:24:29 +08:00
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
if (lws_vhost_foreach_listen_wsi(a->vhost->context, a, check_extant))
|
2014-04-03 08:24:29 +08:00
|
|
|
return 0;
|
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
deal:
|
2021-06-21 08:50:13 +01:00
|
|
|
|
2023-12-13 05:22:14 +00:00
|
|
|
if (!san--)
|
|
|
|
return -1;
|
|
|
|
|
2024-01-02 07:15:12 +00:00
|
|
|
if (a->vhost->iface && (!a->info || !a->info->vh_listen_sockfd)) {
|
2021-06-21 08:50:13 +01:00
|
|
|
|
2018-03-29 13:32:33 +08:00
|
|
|
/*
|
|
|
|
* let's check before we do anything else about the disposition
|
|
|
|
* of the interface he wants to bind to...
|
|
|
|
*/
|
2021-06-21 10:36:36 +01:00
|
|
|
is = lws_socket_bind(a->vhost, NULL, LWS_SOCK_INVALID,
|
|
|
|
a->vhost->listen_port, a->vhost->iface,
|
|
|
|
a->af);
|
2018-03-29 13:32:33 +08:00
|
|
|
lwsl_debug("initial if check says %d\n", is);
|
2018-11-22 17:58:30 +08:00
|
|
|
|
|
|
|
if (is == LWS_ITOSA_BUSY)
|
|
|
|
/* treat as fatal */
|
|
|
|
return -1;
|
|
|
|
|
2018-03-29 13:32:33 +08:00
|
|
|
lws_start_foreach_llp(struct lws_vhost **, pv,
|
2021-06-21 10:36:36 +01:00
|
|
|
cx->no_listener_vhost_list) {
|
|
|
|
if (is >= LWS_ITOSA_USABLE && *pv == a->vhost) {
|
2018-03-29 13:32:33 +08:00
|
|
|
/* on the list and shouldn't be: remove it */
|
2018-11-22 17:58:30 +08:00
|
|
|
lwsl_debug("deferred iface: removing vh %s\n",
|
|
|
|
(*pv)->name);
|
2021-06-21 10:36:36 +01:00
|
|
|
*pv = a->vhost->no_listener_vhost_list;
|
|
|
|
a->vhost->no_listener_vhost_list = NULL;
|
2018-03-29 13:32:33 +08:00
|
|
|
goto done_list;
|
|
|
|
}
|
2021-06-21 10:36:36 +01:00
|
|
|
if (is < LWS_ITOSA_USABLE && *pv == a->vhost)
|
2018-03-29 13:32:33 +08:00
|
|
|
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 */
|
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
lwsl_debug("deferred iface: adding vh %s\n",
|
|
|
|
a->vhost->name);
|
|
|
|
a->vhost->no_listener_vhost_list =
|
|
|
|
cx->no_listener_vhost_list;
|
|
|
|
cx->no_listener_vhost_list = a->vhost;
|
2018-03-29 13:32:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
done_list:
|
|
|
|
|
|
|
|
switch (is) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case LWS_ITOSA_NOT_EXIST:
|
|
|
|
/* can't add it */
|
2021-06-21 10:36:36 +01:00
|
|
|
if (!a->info)
|
2019-08-17 07:54:17 +01:00
|
|
|
return -1;
|
2021-06-21 10:36:36 +01:00
|
|
|
|
|
|
|
/* first time */
|
|
|
|
lwsl_err("%s: VH %s: iface %s port %d DOESN'T EXIST\n",
|
|
|
|
__func__, a->vhost->name, a->vhost->iface,
|
|
|
|
a->vhost->listen_port);
|
|
|
|
|
|
|
|
return (a->info->options &
|
|
|
|
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
|
|
|
|
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ?
|
2019-06-27 12:14:50 +01:00
|
|
|
-1 : 1;
|
2021-06-21 10:36:36 +01:00
|
|
|
|
2018-03-29 13:32:33 +08:00
|
|
|
case LWS_ITOSA_NOT_USABLE:
|
|
|
|
/* can't add it */
|
2021-06-21 10:36:36 +01:00
|
|
|
if (!a->info) /* first time */
|
2019-08-17 07:54:17 +01:00
|
|
|
return -1;
|
2021-06-21 10:36:36 +01:00
|
|
|
|
|
|
|
lwsl_err("%s: VH %s: iface %s port %d NOT USABLE\n",
|
|
|
|
__func__, a->vhost->name, a->vhost->iface,
|
|
|
|
a->vhost->listen_port);
|
|
|
|
|
|
|
|
return (a->info->options &
|
|
|
|
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
|
|
|
|
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ?
|
2019-06-27 12:14:50 +01:00
|
|
|
-1 : 1;
|
2018-03-29 13:32:33 +08:00
|
|
|
}
|
2024-01-02 07:15:12 +00:00
|
|
|
} else {
|
|
|
|
if (a->info && a->info->vh_listen_sockfd) {
|
|
|
|
a->vhost->iface = "inherited";
|
|
|
|
a->vhost->listen_port = a->info->port;
|
|
|
|
}
|
2018-03-29 13:32:33 +08:00
|
|
|
}
|
|
|
|
|
2017-06-23 13:08:46 +08:00
|
|
|
(void)n;
|
2016-01-26 20:56:56 +08:00
|
|
|
#if defined(__linux__)
|
2018-07-08 15:33:10 +08:00
|
|
|
/*
|
2021-06-21 10:36:36 +01:00
|
|
|
* A Unix domain sockets cannot be bound multiple times, even if we
|
|
|
|
* set the SO_REUSE* options on.
|
|
|
|
*
|
|
|
|
* However on recent linux, each thread is able to independently listen.
|
|
|
|
*
|
|
|
|
* So we can assume creating just one listening socket for a multi-
|
|
|
|
* threaded environment will typically work.
|
2018-07-08 15:33:10 +08:00
|
|
|
*/
|
2021-06-21 10:36:36 +01:00
|
|
|
if (a->af != AF_UNIX)
|
|
|
|
limit = cx->count_threads;
|
2016-01-26 20:56:56 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
for (m = 0; m < limit; m++) {
|
2021-03-16 13:32:05 +00:00
|
|
|
|
2024-01-02 07:15:12 +00:00
|
|
|
if (a->info && a->info->vh_listen_sockfd)
|
2024-05-04 15:10:02 +03:00
|
|
|
{
|
|
|
|
#if defined(_WIN32)
|
|
|
|
if (!DuplicateHandle(GetCurrentProcess(),
|
|
|
|
(HANDLE)a->info->vh_listen_sockfd,
|
|
|
|
GetCurrentProcess(), (HANDLE*)&sockfd, 0,
|
|
|
|
FALSE, DUPLICATE_SAME_ACCESS))
|
|
|
|
sockfd = LWS_SOCK_INVALID;
|
2024-10-31 06:20:27 +00:00
|
|
|
#else
|
|
|
|
#if defined(LWS_PLAT_FREERTOS)
|
|
|
|
sockfd = a->info->vh_listen_sockfd;
|
2024-05-04 15:10:02 +03:00
|
|
|
#else
|
|
|
|
sockfd = dup(a->info->vh_listen_sockfd);
|
2024-10-31 06:20:27 +00:00
|
|
|
#endif
|
2024-05-04 15:10:02 +03:00
|
|
|
#endif
|
|
|
|
}
|
2024-01-02 07:15:12 +00:00
|
|
|
else
|
|
|
|
sockfd = lws_fi(&a->vhost->fic, "listenskt") ?
|
2021-06-21 10:36:36 +01:00
|
|
|
LWS_SOCK_INVALID :
|
|
|
|
socket(a->af, SOCK_STREAM, 0);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-03-08 12:04:13 +08:00
|
|
|
if (sockfd == LWS_SOCK_INVALID) {
|
|
|
|
lwsl_err("ERROR opening socket\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2021-06-21 10:36:36 +01:00
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if !defined(LWS_PLAT_FREERTOS)
|
2017-06-23 13:08:46 +08:00
|
|
|
#if (defined(WIN32) || defined(_WIN32)) && defined(SO_EXCLUSIVEADDRUSE)
|
2018-03-08 12:04:13 +08:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
2021-06-21 10:36:36 +01:00
|
|
|
if (!lws_check_opt(a->vhost->options,
|
2018-03-08 12:04:13 +08:00
|
|
|
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);
|
2018-03-29 13:32:33 +08:00
|
|
|
return -1;
|
2018-03-08 12:04:13 +08:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* allow us to restart even if old sockets in TIME_WAIT
|
|
|
|
*/
|
|
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
|
2017-06-23 13:08:46 +08:00
|
|
|
(const void *)&opt, sizeof(opt)) < 0) {
|
|
|
|
lwsl_err("reuseaddr failed\n");
|
|
|
|
compatible_close(sockfd);
|
2018-03-29 13:32:33 +08:00
|
|
|
return -1;
|
2017-06-23 13:08:46 +08:00
|
|
|
}
|
2016-06-04 08:37:39 +08:00
|
|
|
|
2017-09-28 11:29:03 +08:00
|
|
|
#if defined(LWS_WITH_IPV6) && defined(IPV6_V6ONLY)
|
2021-06-21 10:36:36 +01:00
|
|
|
/*
|
|
|
|
* If we have an ipv6 listen socket, it only accepts ipv6.
|
|
|
|
*
|
|
|
|
* There will be a separate ipv4 listen socket if that's
|
|
|
|
* enabled.
|
|
|
|
*/
|
2024-01-02 07:15:12 +00:00
|
|
|
if (a->af == AF_INET6 && (!a->info || !a->info->vh_listen_sockfd) &&
|
2021-06-21 10:36:36 +01:00
|
|
|
setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
|
|
|
|
(const void*)&value, sizeof(value)) < 0) {
|
2024-01-02 07:15:12 +00:00
|
|
|
lwsl_err("ipv6 only failed\n");
|
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
compatible_close(sockfd);
|
|
|
|
return -1;
|
2016-06-04 08:37:39 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-06-23 13:08:46 +08:00
|
|
|
#if defined(__linux__) && defined(SO_REUSEPORT)
|
2018-03-19 08:21:49 +08:00
|
|
|
/* keep coverity happy */
|
2017-06-23 13:08:46 +08:00
|
|
|
#if LWS_MAX_SMP > 1
|
2018-03-08 12:04:13 +08:00
|
|
|
n = 1;
|
2018-03-19 08:21:49 +08:00
|
|
|
#else
|
2021-06-21 10:36:36 +01:00
|
|
|
n = lws_check_opt(a->vhost->options,
|
2018-04-20 21:14:07 +03:00
|
|
|
LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE);
|
2017-06-23 13:08:46 +08:00
|
|
|
#endif
|
2021-10-30 06:14:28 +01:00
|
|
|
if (n || cx->count_threads > 1) /* ... also implied by threads > 1 */
|
2017-06-23 13:08:46 +08:00
|
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
|
|
|
|
(const void *)&opt, sizeof(opt)) < 0) {
|
2024-01-02 07:15:12 +00:00
|
|
|
lwsl_err("reuseport failed\n");
|
2017-06-23 13:08:46 +08:00
|
|
|
compatible_close(sockfd);
|
2018-03-29 13:32:33 +08:00
|
|
|
return -1;
|
2017-06-23 13:08:46 +08:00
|
|
|
}
|
2016-01-26 20:56:56 +08:00
|
|
|
#endif
|
2015-11-02 20:34:12 +08:00
|
|
|
#endif
|
2021-06-21 10:36:36 +01:00
|
|
|
lws_plat_set_socket_options(a->vhost, sockfd, 0);
|
|
|
|
|
2024-01-02 07:15:12 +00:00
|
|
|
if (!a->info || !a->info->vh_listen_sockfd) {
|
|
|
|
is = lws_socket_bind(a->vhost, NULL, sockfd,
|
|
|
|
a->vhost->listen_port,
|
|
|
|
a->vhost->iface, a->af);
|
2014-04-03 08:24:29 +08:00
|
|
|
|
2024-01-02 07:15:12 +00:00
|
|
|
if (is == LWS_ITOSA_BUSY) {
|
|
|
|
/* treat as fatal */
|
|
|
|
compatible_close(sockfd);
|
2018-11-22 17:58:30 +08:00
|
|
|
|
2024-01-02 07:15:12 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2018-11-22 17:58:30 +08:00
|
|
|
|
2024-01-02 07:15:12 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
if (a->vhost->iface)
|
|
|
|
goto deal;
|
|
|
|
return -1;
|
|
|
|
}
|
2018-03-29 13:32:33 +08:00
|
|
|
}
|
2014-04-03 08:24:29 +08:00
|
|
|
|
2020-12-24 16:06:50 +00:00
|
|
|
/*
|
|
|
|
* Create the listen wsi and customize it
|
|
|
|
*/
|
2020-08-27 15:37:14 +01:00
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
lws_context_lock(cx, __func__);
|
2021-06-26 17:24:19 +01:00
|
|
|
wsi = __lws_wsi_create_with_role(cx, m, &role_ops_listen, NULL);
|
2021-06-21 10:36:36 +01:00
|
|
|
lws_context_unlock(cx);
|
2020-12-24 16:06:50 +00:00
|
|
|
if (wsi == NULL) {
|
|
|
|
lwsl_err("Out of mem\n");
|
|
|
|
goto bail;
|
2018-03-08 12:04:13 +08:00
|
|
|
}
|
2021-06-29 13:30:48 +01:00
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
wsi->af = (uint8_t)a->af;
|
2018-09-04 08:06:46 +08:00
|
|
|
|
|
|
|
#ifdef LWS_WITH_UNIX_SOCK
|
2021-06-21 10:36:36 +01:00
|
|
|
if (!LWS_UNIX_SOCK_ENABLED(a->vhost))
|
2018-09-04 08:06:46 +08:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
wsi->unix_skt = 1;
|
2021-06-21 10:36:36 +01:00
|
|
|
a->vhost->listen_port = is;
|
2018-09-04 08:06:46 +08:00
|
|
|
|
2018-11-22 17:58:30 +08:00
|
|
|
lwsl_debug("%s: lws_socket_bind says %d\n", __func__, is);
|
2018-09-04 08:06:46 +08:00
|
|
|
}
|
|
|
|
|
2018-03-08 12:04:13 +08:00
|
|
|
wsi->desc.sockfd = sockfd;
|
2021-06-21 10:36:36 +01:00
|
|
|
wsi->a.protocol = a->vhost->protocols;
|
|
|
|
lws_vhost_bind_wsi(a->vhost, wsi);
|
2018-03-08 12:04:13 +08:00
|
|
|
wsi->listener = 1;
|
2014-04-03 08:24:29 +08:00
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.context->event_loop_ops->init_vhost_listen_wsi)
|
|
|
|
wsi->a.context->event_loop_ops->init_vhost_listen_wsi(wsi);
|
2016-11-30 07:05:13 +08:00
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
pt = &cx->pt[m];
|
2020-08-31 08:12:16 +01:00
|
|
|
lws_pt_lock(pt, __func__);
|
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
if (__insert_wsi_socket_into_fds(cx, wsi)) {
|
2018-03-29 13:32:33 +08:00
|
|
|
lwsl_notice("inserting wsi socket into fds failed\n");
|
2020-08-31 08:12:16 +01:00
|
|
|
lws_pt_unlock(pt);
|
2018-03-08 12:04:13 +08:00
|
|
|
goto bail;
|
2018-03-29 13:32:33 +08:00
|
|
|
}
|
2014-04-03 08:24:29 +08:00
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
lws_dll2_add_tail(&wsi->listen_list, &a->vhost->listen_wsi);
|
2020-08-31 08:12:16 +01:00
|
|
|
lws_pt_unlock(pt);
|
2014-04-03 08:24:29 +08:00
|
|
|
|
2021-05-25 06:09:01 +01:00
|
|
|
#if defined(WIN32) && defined(TCP_FASTOPEN)
|
2021-06-21 10:36:36 +01:00
|
|
|
if (a->vhost->fo_listen_queue) {
|
2021-05-25 06:09:01 +01:00
|
|
|
int optval = 1;
|
|
|
|
if (setsockopt(wsi->desc.sockfd, IPPROTO_TCP,
|
|
|
|
TCP_FASTOPEN,
|
|
|
|
(const char*)&optval, sizeof(optval)) < 0) {
|
2024-10-27 11:39:51 +02:00
|
|
|
#if (_LWS_ENABLED_LOGS & LLL_WARN)
|
2021-05-25 06:09:01 +01:00
|
|
|
int error = LWS_ERRNO;
|
|
|
|
lwsl_warn("%s: TCP_NODELAY failed with error %d\n",
|
|
|
|
__func__, error);
|
2024-10-27 11:39:51 +02:00
|
|
|
#endif
|
2021-05-25 06:09:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#if defined(TCP_FASTOPEN)
|
2021-06-21 10:36:36 +01:00
|
|
|
if (a->vhost->fo_listen_queue) {
|
|
|
|
int qlen = a->vhost->fo_listen_queue;
|
2021-05-25 06:09:01 +01:00
|
|
|
|
|
|
|
if (setsockopt(wsi->desc.sockfd, SOL_TCP, TCP_FASTOPEN,
|
|
|
|
&qlen, sizeof(qlen)))
|
|
|
|
lwsl_warn("%s: TCP_FASTOPEN failed\n", __func__);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2018-03-08 12:04:13 +08:00
|
|
|
n = listen(wsi->desc.sockfd, LWS_SOMAXCONN);
|
|
|
|
if (n < 0) {
|
|
|
|
lwsl_err("listen failed with error %d\n", LWS_ERRNO);
|
2021-06-21 08:50:13 +01:00
|
|
|
lws_dll2_remove(&wsi->listen_list);
|
2018-03-08 12:04:13 +08:00
|
|
|
__remove_wsi_socket_from_fds(wsi);
|
|
|
|
goto bail;
|
|
|
|
}
|
2020-12-25 05:54:19 +00:00
|
|
|
|
2024-01-02 07:15:12 +00:00
|
|
|
if (wsi) {
|
|
|
|
if (a->info && a->info->vh_listen_sockfd)
|
|
|
|
a->vhost->listen_port = a->info->port;
|
|
|
|
|
2021-06-26 17:24:19 +01:00
|
|
|
__lws_lc_tag(a->vhost->context,
|
|
|
|
&a->vhost->context->lcg[LWSLCG_WSI],
|
2021-06-21 10:36:36 +01:00
|
|
|
&wsi->lc, "listen|%s|%s|%d",
|
|
|
|
a->vhost->name,
|
|
|
|
a->vhost->iface ? a->vhost->iface : "",
|
|
|
|
(int)a->vhost->listen_port);
|
2024-01-02 07:15:12 +00:00
|
|
|
}
|
2020-12-25 05:54:19 +00:00
|
|
|
|
2016-04-22 08:53:49 +08:00
|
|
|
} /* for each thread able to independently listen */
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
if (!lws_check_opt(cx->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
|
2017-09-28 11:29:03 +08:00
|
|
|
#ifdef LWS_WITH_UNIX_SOCK
|
2021-06-21 10:36:36 +01:00
|
|
|
if (a->af == AF_UNIX)
|
|
|
|
lwsl_info(" Listening on \"%s\"\n", a->vhost->iface);
|
2016-03-30 22:47:02 -07:00
|
|
|
else
|
|
|
|
#endif
|
2021-06-21 10:36:36 +01:00
|
|
|
lwsl_info(" Listening on %s:%d\n",
|
|
|
|
a->vhost->iface,
|
|
|
|
a->vhost->listen_port);
|
2016-03-30 22:47:02 -07:00
|
|
|
}
|
2014-12-04 23:59:35 +01:00
|
|
|
|
2018-04-27 08:27:16 +08:00
|
|
|
// info->port = vhost->listen_port;
|
|
|
|
|
2014-04-03 08:24:29 +08:00
|
|
|
return 0;
|
2015-12-17 17:03:59 +08:00
|
|
|
|
|
|
|
bail:
|
2024-01-02 07:15:12 +00:00
|
|
|
lwsl_err("%s: bailing\n", __func__);
|
2015-12-17 17:03:59 +08:00
|
|
|
compatible_close(sockfd);
|
|
|
|
|
2018-03-29 13:32:33 +08:00
|
|
|
return -1;
|
2014-04-03 08:24:29 +08:00
|
|
|
}
|
2021-06-21 10:36:36 +01:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
_lws_vhost_init_server(const struct lws_context_creation_info *info,
|
|
|
|
struct lws_vhost *vhost)
|
|
|
|
{
|
|
|
|
struct vh_sock_args a;
|
2022-09-30 00:32:11 +01:00
|
|
|
int n;
|
2021-06-21 10:36:36 +01:00
|
|
|
|
|
|
|
a.info = info;
|
|
|
|
a.vhost = vhost;
|
|
|
|
|
|
|
|
if (info) {
|
|
|
|
vhost->iface = info->iface;
|
|
|
|
vhost->listen_port = info->port;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
return 0;
|
|
|
|
|
2024-05-03 19:24:34 +03:00
|
|
|
if (info && info->vh_listen_sockfd) {
|
|
|
|
a.af = AF_UNSPEC;
|
|
|
|
goto single;
|
|
|
|
}
|
|
|
|
|
2021-06-21 10:36:36 +01:00
|
|
|
/*
|
|
|
|
* Let's figure out what AF(s) we want this vhost to listen on.
|
|
|
|
*
|
|
|
|
* We want AF_UNIX alone if that's what's told
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_UNIX_SOCK)
|
|
|
|
/*
|
|
|
|
* If unix socket, ask for that and we are done
|
|
|
|
*/
|
|
|
|
if (LWS_UNIX_SOCK_ENABLED(vhost)) {
|
|
|
|
a.af = AF_UNIX;
|
|
|
|
goto single;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We may support both ipv4 and ipv6, but get a numeric vhost listen
|
|
|
|
* iface that is unambiguously ipv4 or ipv6, meaning we can only listen
|
|
|
|
* for the related AF then.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (vhost->iface) {
|
|
|
|
uint8_t buf[16];
|
|
|
|
int q;
|
|
|
|
|
|
|
|
q = lws_parse_numeric_address(vhost->iface, buf, sizeof(buf));
|
|
|
|
|
|
|
|
if (q == 4) {
|
|
|
|
a.af = AF_INET;
|
|
|
|
goto single;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (q == 16) {
|
|
|
|
#if defined(LWS_WITH_IPV6)
|
|
|
|
if (LWS_IPV6_ENABLED(vhost)) {
|
|
|
|
a.af = AF_INET6;
|
|
|
|
goto single;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
lwsl_err("%s: ipv6 not supported on %s\n", __func__,
|
|
|
|
vhost->name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ... if we make it here, we would want to listen on AF_INET and
|
|
|
|
* AF_INET6 unless one or the other is forbidden
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_IPV6)
|
|
|
|
if (!(LWS_IPV6_ENABLED(vhost) &&
|
|
|
|
(vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) &&
|
|
|
|
(vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE))) {
|
|
|
|
#endif
|
|
|
|
a.af = AF_INET;
|
2022-09-30 00:32:11 +01:00
|
|
|
n = _lws_vhost_init_server_af(&a);
|
|
|
|
if (n)
|
|
|
|
return n;
|
2021-06-21 10:36:36 +01:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_IPV6)
|
|
|
|
}
|
|
|
|
if (LWS_IPV6_ENABLED(vhost)) {
|
|
|
|
a.af = AF_INET6;
|
|
|
|
goto single;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
single:
|
|
|
|
return _lws_vhost_init_server_af(&a);
|
|
|
|
}
|
|
|
|
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
2014-04-03 08:24:29 +08:00
|
|
|
|
2016-03-28 10:10:43 +08:00
|
|
|
struct lws_vhost *
|
|
|
|
lws_select_vhost(struct lws_context *context, int port, const char *servername)
|
|
|
|
{
|
|
|
|
struct lws_vhost *vhost = context->vhost_list;
|
2016-07-11 09:44:17 +08:00
|
|
|
const char *p;
|
2018-10-10 13:54:43 +08:00
|
|
|
int n, colon;
|
2016-07-11 09:44:17 +08:00
|
|
|
|
2017-10-25 08:00:23 +08:00
|
|
|
n = (int)strlen(servername);
|
2016-07-11 09:44:17 +08:00
|
|
|
colon = n;
|
|
|
|
p = strchr(servername, ':');
|
|
|
|
if (p)
|
2017-10-25 08:00:23 +08:00
|
|
|
colon = lws_ptr_diff(p, servername);
|
2016-07-11 09:44:17 +08:00
|
|
|
|
2017-03-07 16:06:05 +08:00
|
|
|
/* Priotity 1: first try exact matches */
|
2016-03-28 10:10:43 +08:00
|
|
|
|
|
|
|
while (vhost) {
|
|
|
|
if (port == vhost->listen_port &&
|
2020-12-12 06:21:40 +00:00
|
|
|
!strncmp(vhost->name, servername, (unsigned int)colon)) {
|
2016-03-28 10:10:43 +08:00
|
|
|
lwsl_info("SNI: Found: %s\n", servername);
|
|
|
|
return vhost;
|
|
|
|
}
|
|
|
|
vhost = vhost->vhost_next;
|
|
|
|
}
|
|
|
|
|
2016-07-11 09:44:17 +08:00
|
|
|
/*
|
2017-03-07 16:06:05 +08:00
|
|
|
* Priority 2: if no exact matches, try matching *.vhost-name
|
2016-07-11 09:44:17 +08:00
|
|
|
* 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) {
|
2018-10-10 13:54:43 +08:00
|
|
|
int m = (int)strlen(vhost->name);
|
2018-09-04 08:06:46 +08:00
|
|
|
if (port && port == vhost->listen_port &&
|
2016-07-11 09:44:17 +08:00
|
|
|
m <= (colon - 2) &&
|
|
|
|
servername[colon - m - 1] == '.' &&
|
2020-12-12 06:21:40 +00:00
|
|
|
!strncmp(vhost->name, servername + colon - m, (unsigned int)m)) {
|
2016-07-11 09:44:17 +08:00
|
|
|
lwsl_info("SNI: Found %s on wildcard: %s\n",
|
|
|
|
servername, vhost->name);
|
|
|
|
return vhost;
|
|
|
|
}
|
|
|
|
vhost = vhost->vhost_next;
|
|
|
|
}
|
|
|
|
|
2017-03-07 16:06:05 +08:00
|
|
|
/* Priority 3: match the first vhost on our port */
|
|
|
|
|
|
|
|
vhost = context->vhost_list;
|
|
|
|
while (vhost) {
|
2018-09-04 08:06:46 +08:00
|
|
|
if (port && port == vhost->listen_port) {
|
2018-05-04 12:05:56 +08:00
|
|
|
lwsl_info("%s: vhost match to %s based on port %d\n",
|
|
|
|
__func__, vhost->name, port);
|
2017-03-07 16:06:05 +08:00
|
|
|
return vhost;
|
|
|
|
}
|
|
|
|
vhost = vhost->vhost_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match */
|
|
|
|
|
2016-03-28 10:10:43 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-04-08 21:03:32 +03:00
|
|
|
static const struct lws_mimetype {
|
|
|
|
const char *extension;
|
|
|
|
const char *mimetype;
|
|
|
|
} server_mimetypes[] = {
|
|
|
|
{ ".html", "text/html" },
|
|
|
|
{ ".htm", "text/html" },
|
|
|
|
{ ".js", "text/javascript" },
|
|
|
|
{ ".css", "text/css" },
|
|
|
|
{ ".png", "image/png" },
|
|
|
|
{ ".jpg", "image/jpeg" },
|
|
|
|
{ ".jpeg", "image/jpeg" },
|
|
|
|
{ ".ico", "image/x-icon" },
|
|
|
|
{ ".gif", "image/gif" },
|
|
|
|
{ ".svg", "image/svg+xml" },
|
|
|
|
{ ".ttf", "application/x-font-ttf" },
|
|
|
|
{ ".otf", "application/font-woff" },
|
|
|
|
{ ".woff", "application/font-woff" },
|
|
|
|
{ ".woff2", "application/font-woff2" },
|
|
|
|
{ ".gz", "application/gzip" },
|
|
|
|
{ ".txt", "text/plain" },
|
|
|
|
{ ".xml", "application/xml" },
|
|
|
|
{ ".json", "application/json" },
|
2021-04-12 06:35:52 +01:00
|
|
|
{ ".mjs", "text/javascript" },
|
2019-04-08 21:03:32 +03:00
|
|
|
};
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
const char *
|
2016-07-03 09:20:11 +08:00
|
|
|
lws_get_mimetype(const char *file, const struct lws_http_mount *m)
|
2016-03-28 10:10:43 +08:00
|
|
|
{
|
2019-04-08 21:03:32 +03:00
|
|
|
const struct lws_protocol_vhost_options *pvo;
|
|
|
|
size_t n = strlen(file), len, i;
|
|
|
|
const char *fallback_mimetype = NULL;
|
|
|
|
const struct lws_mimetype *mt;
|
|
|
|
|
|
|
|
/* prioritize user-defined mimetypes */
|
|
|
|
for (pvo = m ? m->extra_mimetypes : NULL; pvo; pvo = pvo->next) {
|
|
|
|
/* ie, match anything */
|
|
|
|
if (!fallback_mimetype && pvo->name[0] == '*') {
|
|
|
|
fallback_mimetype = pvo->value;
|
|
|
|
continue;
|
|
|
|
}
|
2016-05-06 08:02:57 +08:00
|
|
|
|
2019-04-08 21:03:32 +03:00
|
|
|
len = strlen(pvo->name);
|
|
|
|
if (n > len && !strcasecmp(&file[n - len], pvo->name)) {
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_info("%s: match to user mimetype: %s\n", __func__,
|
|
|
|
pvo->value);
|
2016-08-13 11:17:53 +02:00
|
|
|
return pvo->value;
|
2019-04-08 21:03:32 +03:00
|
|
|
}
|
|
|
|
}
|
2016-08-13 11:17:53 +02:00
|
|
|
|
2019-04-08 21:03:32 +03:00
|
|
|
/* fallback to server-defined mimetypes */
|
|
|
|
for (i = 0; i < LWS_ARRAY_SIZE(server_mimetypes); ++i) {
|
|
|
|
mt = &server_mimetypes[i];
|
|
|
|
|
|
|
|
len = strlen(mt->extension);
|
|
|
|
if (n > len && !strcasecmp(&file[n - len], mt->extension)) {
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_info("%s: match to server mimetype: %s\n", __func__,
|
|
|
|
mt->mimetype);
|
2019-04-08 21:03:32 +03:00
|
|
|
return mt->mimetype;
|
|
|
|
}
|
|
|
|
}
|
2016-05-14 10:00:21 +08:00
|
|
|
|
2019-04-08 21:03:32 +03:00
|
|
|
/* fallback to '*' if defined */
|
|
|
|
if (fallback_mimetype) {
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_info("%s: match to any mimetype: %s\n", __func__,
|
|
|
|
fallback_mimetype);
|
2019-04-08 21:03:32 +03:00
|
|
|
return fallback_mimetype;
|
2016-05-14 10:00:21 +08:00
|
|
|
}
|
|
|
|
|
2016-03-28 10:10:43 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2019-04-08 21:03:32 +03:00
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2017-03-03 12:38:10 +08:00
|
|
|
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;
|
|
|
|
}
|
2016-03-28 10:10:43 +08:00
|
|
|
|
2016-05-14 10:00:21 +08:00
|
|
|
static int
|
|
|
|
lws_http_serve(struct lws *wsi, char *uri, const char *origin,
|
|
|
|
const struct lws_http_mount *m)
|
2016-03-28 10:10:43 +08:00
|
|
|
{
|
2016-05-19 15:28:31 +08:00
|
|
|
const struct lws_protocol_vhost_options *pvo = m->interpret;
|
|
|
|
struct lws_process_html_args args;
|
2017-03-08 11:11:41 +08:00
|
|
|
const char *mimetype;
|
2017-11-30 12:40:46 +08:00
|
|
|
#if !defined(_WIN32_WCE)
|
2017-03-03 12:38:10 +08:00
|
|
|
const struct lws_plat_file_ops *fops;
|
2017-03-08 11:11:41 +08:00
|
|
|
const char *vpath;
|
2017-03-03 12:38:10 +08:00
|
|
|
lws_fop_flags_t fflags = LWS_O_RDONLY;
|
2017-06-09 20:20:42 +08:00
|
|
|
#if defined(WIN32) && defined(LWS_HAVE__STAT32I64)
|
|
|
|
struct _stat32i64 st;
|
|
|
|
#else
|
2016-04-13 11:49:07 +08:00
|
|
|
struct stat st;
|
2017-06-09 20:20:42 +08:00
|
|
|
#endif
|
2016-07-23 14:18:25 +08:00
|
|
|
int spin = 0;
|
2016-05-05 13:28:04 +02:00
|
|
|
#endif
|
2018-08-25 12:27:00 +08:00
|
|
|
char path[256], sym[2048];
|
2016-04-22 08:53:49 +08:00
|
|
|
unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
|
|
|
|
unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
|
2019-08-18 10:35:43 +01:00
|
|
|
#if !defined(WIN32) && !defined(LWS_PLAT_FREERTOS)
|
2016-04-26 22:52:16 +02:00
|
|
|
size_t len;
|
2016-04-26 22:38:42 +02:00
|
|
|
#endif
|
2016-07-23 14:18:25 +08:00
|
|
|
int n;
|
2016-03-28 10:10:43 +08:00
|
|
|
|
2018-03-07 19:57:34 +08:00
|
|
|
wsi->handling_404 = 0;
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (!wsi->a.vhost)
|
2018-03-19 07:59:42 +08:00
|
|
|
return -1;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.vhost->http.error_document_404 &&
|
|
|
|
!strcmp(uri, wsi->a.vhost->http.error_document_404))
|
2018-03-07 19:57:34 +08:00
|
|
|
wsi->handling_404 = 1;
|
2018-04-27 15:20:56 +08:00
|
|
|
#endif
|
2018-03-07 19:57:34 +08:00
|
|
|
|
2016-09-15 02:22:57 +08:00
|
|
|
lws_snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
|
2016-03-28 10:10:43 +08:00
|
|
|
|
2017-11-30 12:40:46 +08:00
|
|
|
#if !defined(_WIN32_WCE)
|
2017-03-08 11:11:41 +08:00
|
|
|
|
|
|
|
fflags |= lws_vfs_prepare_flags(wsi);
|
|
|
|
|
2016-04-13 11:49:07 +08:00
|
|
|
do {
|
|
|
|
spin++;
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
fops = lws_vfs_select_fops(wsi->a.context->fops, path, &vpath);
|
2017-03-03 12:38:10 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (wsi->http.fop_fd)
|
|
|
|
lws_vfs_file_close(&wsi->http.fop_fd);
|
2017-03-03 12:38:10 +08:00
|
|
|
|
2022-02-17 06:37:42 +00:00
|
|
|
wsi->http.fop_fd = fops->LWS_FOP_OPEN(fops, wsi->a.context->fops,
|
2017-03-03 12:38:10 +08:00
|
|
|
path, vpath, &fflags);
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!wsi->http.fop_fd) {
|
2018-04-13 06:43:11 +08:00
|
|
|
lwsl_info("%s: Unable to open '%s': errno %d\n",
|
|
|
|
__func__, path, errno);
|
2017-03-03 12:38:10 +08:00
|
|
|
|
2018-07-16 09:34:39 +08:00
|
|
|
return 1;
|
2017-03-03 12:38:10 +08:00
|
|
|
}
|
2016-04-13 11:49:07 +08:00
|
|
|
|
2017-03-03 12:38:10 +08:00
|
|
|
/* if it can't be statted, don't try */
|
|
|
|
if (fflags & LWS_FOP_FLAG_VIRTUAL)
|
|
|
|
break;
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_PLAT_FREERTOS)
|
2017-04-03 14:09:37 +08:00
|
|
|
break;
|
|
|
|
#endif
|
2017-03-17 11:43:45 +08:00
|
|
|
#if !defined(WIN32)
|
2017-12-01 11:09:32 +08:00
|
|
|
if (fstat(wsi->http.fop_fd->fd, &st)) {
|
2016-04-25 10:04:49 +08:00
|
|
|
lwsl_info("unable to stat %s\n", path);
|
2018-07-16 09:34:39 +08:00
|
|
|
goto notfound;
|
2016-04-13 11:49:07 +08:00
|
|
|
}
|
2017-06-09 20:20:42 +08:00
|
|
|
#else
|
|
|
|
#if defined(LWS_HAVE__STAT32I64)
|
2021-09-09 22:14:07 +08:00
|
|
|
{
|
|
|
|
WCHAR buf[MAX_PATH];
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, path, -1, buf, LWS_ARRAY_SIZE(buf));
|
|
|
|
if (_wstat32i64(buf, &st)) {
|
|
|
|
lwsl_info("unable to stat %s\n", path);
|
|
|
|
goto notfound;
|
|
|
|
}
|
2017-06-09 20:20:42 +08:00
|
|
|
}
|
2017-03-17 11:43:45 +08:00
|
|
|
#else
|
|
|
|
if (stat(path, &st)) {
|
|
|
|
lwsl_info("unable to stat %s\n", path);
|
2018-07-16 09:34:39 +08:00
|
|
|
goto notfound;
|
2017-03-17 11:43:45 +08:00
|
|
|
}
|
2017-06-09 20:20:42 +08:00
|
|
|
#endif
|
2017-03-17 11:43:45 +08:00
|
|
|
#endif
|
2016-04-13 11:49:07 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.fop_fd->mod_time = (uint32_t)st.st_mtime;
|
2017-03-03 12:38:10 +08:00
|
|
|
fflags |= LWS_FOP_FLAG_MOD_TIME_VALID;
|
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if !defined(WIN32) && !defined(LWS_PLAT_FREERTOS)
|
2016-04-13 11:49:07 +08:00
|
|
|
if ((S_IFMT & st.st_mode) == S_IFLNK) {
|
2020-12-12 06:21:40 +00:00
|
|
|
len = (size_t)readlink(path, sym, sizeof(sym) - 1);
|
2016-04-23 07:49:57 +08:00
|
|
|
if (len) {
|
2016-04-13 11:49:07 +08:00
|
|
|
lwsl_err("Failed to read link %s\n", path);
|
2018-07-16 09:34:39 +08:00
|
|
|
goto notfound;
|
2016-04-13 11:49:07 +08:00
|
|
|
}
|
2016-04-23 07:49:57 +08:00
|
|
|
sym[len] = '\0';
|
2016-04-13 11:49:07 +08:00
|
|
|
lwsl_debug("symlink %s -> %s\n", path, sym);
|
2016-09-15 02:22:57 +08:00
|
|
|
lws_snprintf(path, sizeof(path) - 1, "%s", sym);
|
2016-04-13 11:49:07 +08:00
|
|
|
}
|
2016-04-13 11:42:53 +08:00
|
|
|
#endif
|
2016-04-13 11:49:07 +08:00
|
|
|
if ((S_IFMT & st.st_mode) == S_IFDIR) {
|
|
|
|
lwsl_debug("default filename append to dir\n");
|
2020-03-23 11:26:23 +01:00
|
|
|
lws_snprintf(path, sizeof(path) - 1, "%s/%s/%s",
|
|
|
|
origin, uri, m->def ? m->def : "index.html");
|
2016-04-13 11:49:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} while ((S_IFMT & st.st_mode) != S_IFREG && spin < 5);
|
|
|
|
|
2016-04-22 08:53:49 +08:00
|
|
|
if (spin == 5)
|
2016-04-13 11:49:07 +08:00
|
|
|
lwsl_err("symlink loop %s \n", path);
|
2016-04-22 08:53:49 +08:00
|
|
|
|
2017-07-07 08:32:04 +08:00
|
|
|
n = sprintf(sym, "%08llX%08lX",
|
2017-12-01 11:09:32 +08:00
|
|
|
(unsigned long long)lws_vfs_get_length(wsi->http.fop_fd),
|
|
|
|
(unsigned long)lws_vfs_get_mod_time(wsi->http.fop_fd));
|
2016-04-22 08:53:49 +08:00
|
|
|
|
2016-12-12 13:36:25 +08:00
|
|
|
/* 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: */
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->frag_index[WSI_TOKEN_HTTP_RANGE] = 0;
|
2016-12-12 13:36:25 +08:00
|
|
|
|
2016-04-22 08:53:49 +08:00
|
|
|
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
|
|
|
|
*/
|
2017-03-03 12:38:10 +08:00
|
|
|
if (!strcmp(sym, lws_hdr_simple_ptr(wsi,
|
|
|
|
WSI_TOKEN_HTTP_IF_NONE_MATCH))) {
|
2016-04-22 08:53:49 +08:00
|
|
|
|
2018-08-13 16:49:58 +08:00
|
|
|
char cache_control[50], *cc = "no-store";
|
|
|
|
int cclen = 8;
|
|
|
|
|
2016-04-23 07:14:03 +08:00
|
|
|
lwsl_debug("%s: ETAG match %s %s\n", __func__,
|
|
|
|
uri, origin);
|
2016-04-22 08:53:49 +08:00
|
|
|
|
|
|
|
/* we don't need to send the payload */
|
2017-03-08 07:51:47 +08:00
|
|
|
if (lws_add_http_header_status(wsi,
|
2018-08-25 12:27:00 +08:00
|
|
|
HTTP_STATUS_NOT_MODIFIED, &p, end)) {
|
|
|
|
lwsl_err("%s: failed adding not modified\n",
|
|
|
|
__func__);
|
2016-04-22 08:53:49 +08:00
|
|
|
return -1;
|
2018-08-25 12:27:00 +08:00
|
|
|
}
|
2016-08-27 17:07:06 +08:00
|
|
|
|
2016-04-22 08:53:49 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_ETAG,
|
|
|
|
(unsigned char *)sym, n, &p, end))
|
|
|
|
return -1;
|
2016-08-27 17:07:06 +08:00
|
|
|
|
2018-08-13 16:49:58 +08:00
|
|
|
/* but we still need to send cache control... */
|
|
|
|
|
2018-08-23 11:48:17 +08:00
|
|
|
if (m->cache_max_age && m->cache_reusable) {
|
2018-08-13 16:49:58 +08:00
|
|
|
if (!m->cache_revalidate) {
|
|
|
|
cc = cache_control;
|
2018-11-23 08:47:56 +08:00
|
|
|
cclen = sprintf(cache_control,
|
|
|
|
"%s, max-age=%u",
|
|
|
|
intermediates[wsi->cache_intermediaries],
|
|
|
|
m->cache_max_age);
|
2018-08-13 16:49:58 +08:00
|
|
|
} else {
|
|
|
|
cc = cache_control;
|
2018-11-23 08:47:56 +08:00
|
|
|
cclen = sprintf(cache_control,
|
|
|
|
"must-revalidate, %s, max-age=%u",
|
|
|
|
intermediates[wsi->cache_intermediaries],
|
|
|
|
m->cache_max_age);
|
2018-08-13 16:49:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_CACHE_CONTROL,
|
2018-08-13 16:49:58 +08:00
|
|
|
(unsigned char *)cc, cclen, &p, end))
|
|
|
|
return -1;
|
|
|
|
|
2016-04-22 08:53:49 +08:00
|
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
|
|
|
return -1;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
|
2017-10-13 10:33:02 +08:00
|
|
|
LWS_WRITE_HTTP_HEADERS |
|
|
|
|
LWS_WRITE_H2_STREAM_END);
|
2020-12-12 06:21:40 +00:00
|
|
|
if (n != lws_ptr_diff(p, start)) {
|
2017-02-04 13:09:00 +01:00
|
|
|
lwsl_err("_write returned %d from %ld\n", n,
|
|
|
|
(long)(p - start));
|
2016-04-22 08:53:49 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
lws_vfs_file_close(&wsi->http.fop_fd);
|
2017-03-03 12:38:10 +08:00
|
|
|
|
2018-07-16 09:34:39 +08:00
|
|
|
if (lws_http_transaction_completed(wsi))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
2016-04-22 08:53:49 +08:00
|
|
|
}
|
2016-04-13 11:49:07 +08:00
|
|
|
}
|
|
|
|
|
2016-04-22 08:53:49 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,
|
|
|
|
(unsigned char *)sym, n, &p, end))
|
|
|
|
return -1;
|
2016-05-05 13:28:04 +02:00
|
|
|
#endif
|
2016-04-22 08:53:49 +08:00
|
|
|
|
2016-07-03 09:20:11 +08:00
|
|
|
mimetype = lws_get_mimetype(path, m);
|
2016-03-28 10:10:43 +08:00
|
|
|
if (!mimetype) {
|
2018-10-31 10:44:44 +08:00
|
|
|
lwsl_info("unknown mimetype for %s\n", path);
|
|
|
|
if (lws_return_http_status(wsi,
|
|
|
|
HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL) ||
|
|
|
|
lws_http_transaction_completed(wsi))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
2016-03-28 10:10:43 +08:00
|
|
|
}
|
2016-08-13 11:17:53 +02:00
|
|
|
if (!mimetype[0])
|
|
|
|
lwsl_debug("sending no mimetype for %s\n", path);
|
2016-03-28 10:10:43 +08:00
|
|
|
|
2016-05-19 15:28:31 +08:00
|
|
|
wsi->sending_chunked = 0;
|
2019-04-05 21:13:59 +08:00
|
|
|
wsi->interpreting = 0;
|
2016-05-19 15:28:31 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* check if this is in the list of file suffixes to be interpreted by
|
|
|
|
* a protocol
|
|
|
|
*/
|
|
|
|
while (pvo) {
|
2017-10-25 08:00:23 +08:00
|
|
|
n = (int)strlen(path);
|
2016-05-19 15:28:31 +08:00
|
|
|
if (n > (int)strlen(pvo->name) &&
|
2020-12-12 06:21:40 +00:00
|
|
|
!strcmp(&path[(unsigned int)n - strlen(pvo->name)], pvo->name)) {
|
2018-01-14 20:09:41 +08:00
|
|
|
wsi->interpreting = 1;
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream)
|
2018-01-14 20:09:41 +08:00
|
|
|
wsi->sending_chunked = 1;
|
2019-04-05 21:13:59 +08:00
|
|
|
|
2019-10-27 12:55:13 +00:00
|
|
|
wsi->protocol_interpret_idx = (char)(
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
lws_vhost_name_to_protocol(wsi->a.vhost,
|
2019-04-05 21:13:59 +08:00
|
|
|
pvo->value) -
|
2019-10-27 12:55:13 +00:00
|
|
|
&lws_get_vhost(wsi)->protocols[0]);
|
2019-04-05 21:13:59 +08:00
|
|
|
|
|
|
|
lwsl_debug("want %s interpreted by %s (pcol is %s)\n", path,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->protocols[
|
2019-04-05 21:13:59 +08:00
|
|
|
(int)wsi->protocol_interpret_idx].name,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.protocol->name);
|
|
|
|
if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[
|
2019-04-05 21:13:59 +08:00
|
|
|
(int)wsi->protocol_interpret_idx], __func__))
|
|
|
|
return -1;
|
|
|
|
|
2016-05-19 15:28:31 +08:00
|
|
|
if (lws_ensure_user_space(wsi))
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pvo = pvo->next;
|
|
|
|
}
|
|
|
|
|
2019-04-05 21:13:59 +08:00
|
|
|
if (wsi->sending_chunked) {
|
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_TRANSFER_ENCODING,
|
|
|
|
(unsigned char *)"chunked", 7,
|
|
|
|
&p, end))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-05-19 15:28:31 +08:00
|
|
|
if (m->protocol) {
|
|
|
|
const struct lws_protocols *pp = lws_vhost_name_to_protocol(
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost, m->protocol);
|
2016-05-19 15:28:31 +08:00
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
if (lws_bind_protocol(wsi, pp, __func__))
|
2018-07-16 09:34:39 +08:00
|
|
|
return -1;
|
2016-05-19 15:28:31 +08:00
|
|
|
args.p = (char *)p;
|
2017-10-25 08:00:23 +08:00
|
|
|
args.max_len = lws_ptr_diff(end, p);
|
2016-05-19 15:28:31 +08:00
|
|
|
if (pp->callback(wsi, LWS_CALLBACK_ADD_HEADERS,
|
|
|
|
wsi->user_space, &args, 0))
|
|
|
|
return -1;
|
|
|
|
p = (unsigned char *)args.p;
|
|
|
|
}
|
|
|
|
|
2018-11-15 16:33:54 +08:00
|
|
|
*p = '\0';
|
2017-10-25 08:00:23 +08:00
|
|
|
n = lws_serve_http_file(wsi, path, mimetype, (char *)start,
|
|
|
|
lws_ptr_diff(p, start));
|
2016-04-06 16:15:40 +08:00
|
|
|
|
2016-03-28 10:10:43 +08:00
|
|
|
if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
|
|
|
|
return -1; /* error or can't reuse connection: close the socket */
|
|
|
|
|
|
|
|
return 0;
|
2018-07-16 09:34:39 +08:00
|
|
|
|
|
|
|
notfound:
|
|
|
|
|
|
|
|
return 1;
|
2016-03-28 10:10:43 +08:00
|
|
|
}
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
2016-03-28 10:10:43 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
2016-06-26 06:29:20 +08:00
|
|
|
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;
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
hm = wsi->a.vhost->http.mount_list;
|
2016-06-26 06:29:20 +08:00
|
|
|
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)
|
|
|
|
) {
|
2021-01-06 15:08:22 +00:00
|
|
|
#if defined(LWS_WITH_SYS_METRICS)
|
|
|
|
lws_metrics_tag_wsi_add(wsi, "mnt", hm->mountpoint);
|
|
|
|
#endif
|
|
|
|
|
2023-12-12 05:55:49 +00:00
|
|
|
if (hm->origin_protocol == LWSMPRO_NO_MOUNT)
|
|
|
|
return NULL;
|
|
|
|
|
2016-06-26 06:29:20 +08:00
|
|
|
if (hm->origin_protocol == LWSMPRO_CALLBACK ||
|
|
|
|
((hm->origin_protocol == LWSMPRO_CGI ||
|
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||
|
2019-03-22 06:22:40 +08:00
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||
|
2021-02-01 11:48:04 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
|
2020-10-10 06:52:40 +01:00
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI) ||
|
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
|
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_DELETE_URI) ||
|
2021-02-01 11:48:04 +00:00
|
|
|
#endif
|
2019-08-01 12:56:29 +01:00
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_HEAD_URI) ||
|
2020-02-28 10:31:04 +00:00
|
|
|
#if defined(LWS_ROLE_H2)
|
2019-12-23 11:31:57 +00:00
|
|
|
(wsi->mux_substream &&
|
2017-10-16 12:52:32 +08:00
|
|
|
lws_hdr_total_length(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_PATH)) ||
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
2016-06-26 06:29:20 +08:00
|
|
|
hm->protocol) &&
|
|
|
|
hm->mountpoint_len > best)) {
|
|
|
|
best = hm->mountpoint_len;
|
|
|
|
hit = hm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hm = hm->mount_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hit;
|
|
|
|
}
|
2018-04-27 15:20:56 +08:00
|
|
|
#endif
|
2016-06-26 06:29:20 +08:00
|
|
|
|
2020-02-28 09:29:25 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_BASIC_AUTH) && !defined(LWS_PLAT_FREERTOS) && defined(LWS_WITH_FILE_OPS)
|
2016-12-03 15:13:15 +08:00
|
|
|
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;
|
|
|
|
|
2018-06-23 12:56:21 +08:00
|
|
|
fd = lws_open(filename, O_RDONLY);
|
2016-12-03 15:13:15 +08:00
|
|
|
if (fd < 0) {
|
|
|
|
lwsl_err("can't open auth file: %s\n", filename);
|
2018-04-19 08:41:16 +08:00
|
|
|
return 0;
|
2016-12-03 15:13:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (pos == n) {
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (int)read(fd, buf, sizeof(buf));
|
2016-12-03 15:13:15 +08:00
|
|
|
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;
|
|
|
|
}
|
2018-04-12 15:56:38 +08:00
|
|
|
#endif
|
2016-12-03 15:13:15 +08:00
|
|
|
|
2020-02-28 09:29:25 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_BASIC_AUTH)
|
|
|
|
|
2018-11-28 12:16:01 +08:00
|
|
|
int
|
2016-12-03 15:13:15 +08:00
|
|
|
lws_unauthorised_basic_auth(struct lws *wsi)
|
|
|
|
{
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
2016-12-03 15:13:15 +08:00
|
|
|
unsigned char *start = pt->serv_buf + LWS_PRE,
|
2018-09-04 08:06:46 +08:00
|
|
|
*p = start, *end = p + 2048;
|
2016-12-03 15:13:15 +08:00
|
|
|
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;
|
|
|
|
|
2019-04-03 10:18:17 +03:00
|
|
|
if (lws_add_http_header_content_length(wsi, 0, &p, end))
|
|
|
|
return -1;
|
|
|
|
|
2016-12-03 15:13:15 +08:00
|
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
|
|
|
return -1;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_HTTP_HEADERS |
|
2017-10-16 12:52:32 +08:00
|
|
|
LWS_WRITE_H2_STREAM_END);
|
2016-12-03 15:13:15 +08:00
|
|
|
if (n < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return lws_http_transaction_completed(wsi);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-02-28 09:29:25 +00:00
|
|
|
#endif
|
|
|
|
|
2017-06-12 13:36:24 +08:00
|
|
|
int lws_clean_url(char *p)
|
|
|
|
{
|
2017-07-21 20:04:02 +08:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-12 13:36:24 +08:00
|
|
|
while (*p) {
|
|
|
|
if (p[0] == '/' && p[1] == '/') {
|
|
|
|
char *p1 = p;
|
|
|
|
while (*p1) {
|
|
|
|
*p1 = p1[1];
|
|
|
|
p1++;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-06 09:30:32 +08:00
|
|
|
static const unsigned char methods[] = {
|
|
|
|
WSI_TOKEN_GET_URI,
|
|
|
|
WSI_TOKEN_POST_URI,
|
2020-02-28 10:31:04 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
|
2017-09-06 09:30:32 +08:00
|
|
|
WSI_TOKEN_OPTIONS_URI,
|
|
|
|
WSI_TOKEN_PUT_URI,
|
|
|
|
WSI_TOKEN_PATCH_URI,
|
|
|
|
WSI_TOKEN_DELETE_URI,
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
2017-09-06 09:30:32 +08:00
|
|
|
WSI_TOKEN_CONNECT,
|
2017-10-13 10:33:02 +08:00
|
|
|
WSI_TOKEN_HEAD_URI,
|
2017-09-28 11:29:03 +08:00
|
|
|
#ifdef LWS_WITH_HTTP2
|
2017-09-06 09:30:32 +08:00
|
|
|
WSI_TOKEN_HTTP_COLON_PATH,
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2019-02-20 07:47:48 +08:00
|
|
|
int
|
2017-09-06 09:30:32 +08:00
|
|
|
lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)
|
|
|
|
{
|
|
|
|
int n, count = 0;
|
2015-01-10 19:01:52 -08:00
|
|
|
|
2018-08-16 19:10:32 +08:00
|
|
|
for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++)
|
2015-01-10 19:01:52 -08:00
|
|
|
if (lws_hdr_total_length(wsi, methods[n]))
|
|
|
|
count++;
|
|
|
|
if (!count) {
|
2014-10-08 12:00:53 +08:00
|
|
|
lwsl_warn("Missing URI in HTTP request\n");
|
2017-09-06 09:30:32 +08:00
|
|
|
return -1;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (count != 1 &&
|
2020-02-28 10:31:04 +00:00
|
|
|
!((wsi->mux_substream || wsi->h2_stream_carries_ws)
|
|
|
|
#if defined(LWS_ROLE_H2)
|
|
|
|
&&
|
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH)
|
|
|
|
#endif
|
|
|
|
)) {
|
2015-01-10 19:01:52 -08:00
|
|
|
lwsl_warn("multiple methods?\n");
|
2017-09-06 09:30:32 +08:00
|
|
|
return -1;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
|
|
|
|
2018-08-16 19:10:32 +08:00
|
|
|
for (n = 0; n < (int)LWS_ARRAY_SIZE(methods); n++)
|
2015-01-10 19:01:52 -08:00
|
|
|
if (lws_hdr_total_length(wsi, methods[n])) {
|
2017-09-06 09:30:32 +08:00
|
|
|
*puri_ptr = lws_hdr_simple_ptr(wsi, methods[n]);
|
|
|
|
*puri_len = lws_hdr_total_length(wsi, methods[n]);
|
|
|
|
return n;
|
2015-01-10 19:01:52 -08:00
|
|
|
}
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-09-06 09:30:32 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-02-28 09:29:25 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_BASIC_AUTH)
|
|
|
|
|
2018-11-28 12:16:01 +08:00
|
|
|
enum lws_check_basic_auth_results
|
2019-12-12 18:45:00 +00:00
|
|
|
lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file,
|
|
|
|
unsigned int auth_mode)
|
2018-11-28 12:16:01 +08:00
|
|
|
{
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2018-11-28 12:16:01 +08:00
|
|
|
char b64[160], plain[(sizeof(b64) * 3) / 4], *pcolon;
|
2019-12-12 18:45:00 +00:00
|
|
|
int m, ml, fi, bar;
|
2018-11-28 12:16:01 +08:00
|
|
|
|
2019-12-12 18:45:00 +00:00
|
|
|
if (!basic_auth_login_file && auth_mode == LWSAUTHM_DEFAULT)
|
2018-11-28 12:16:01 +08:00
|
|
|
return LCBA_CONTINUE;
|
|
|
|
|
|
|
|
/* Did he send auth? */
|
|
|
|
ml = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_AUTHORIZATION);
|
|
|
|
if (!ml)
|
|
|
|
return LCBA_FAILED_AUTH;
|
|
|
|
|
|
|
|
/* Disallow fragmentation monkey business */
|
|
|
|
|
|
|
|
fi = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_AUTHORIZATION];
|
|
|
|
if (wsi->http.ah->frags[fi].nfrag) {
|
|
|
|
lwsl_err("fragmented basic auth header not allowed\n");
|
|
|
|
return LCBA_FAILED_AUTH;
|
|
|
|
}
|
|
|
|
|
|
|
|
m = lws_hdr_copy(wsi, b64, sizeof(b64),
|
|
|
|
WSI_TOKEN_HTTP_AUTHORIZATION);
|
|
|
|
if (m < 7) {
|
|
|
|
lwsl_err("b64 auth too long\n");
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
b64[5] = '\0';
|
|
|
|
if (strcasecmp(b64, "Basic")) {
|
|
|
|
lwsl_err("auth missing basic: %s\n", b64);
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It'll be like Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l */
|
|
|
|
|
|
|
|
m = lws_b64_decode_string(b64 + 6, plain, sizeof(plain) - 1);
|
|
|
|
if (m < 0) {
|
|
|
|
lwsl_err("plain auth too long\n");
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
plain[m] = '\0';
|
|
|
|
pcolon = strchr(plain, ':');
|
|
|
|
if (!pcolon) {
|
|
|
|
lwsl_err("basic auth format broken\n");
|
|
|
|
return LCBA_END_TRANSACTION;
|
|
|
|
}
|
2019-12-12 18:45:00 +00:00
|
|
|
|
|
|
|
switch (auth_mode) {
|
|
|
|
case LWSAUTHM_DEFAULT:
|
|
|
|
if (lws_find_string_in_file(basic_auth_login_file, plain, m))
|
|
|
|
break;
|
|
|
|
lwsl_err("%s: basic auth lookup failed\n", __func__);
|
|
|
|
return LCBA_FAILED_AUTH;
|
|
|
|
|
|
|
|
case LWSAUTHM_BASIC_AUTH_CALLBACK:
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
bar = wsi->a.protocol->callback(wsi,
|
2019-12-12 18:45:00 +00:00
|
|
|
LWS_CALLBACK_VERIFY_BASIC_AUTHORIZATION,
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->user_space, plain, (unsigned int)m);
|
2019-12-12 18:45:00 +00:00
|
|
|
if (!bar)
|
|
|
|
return LCBA_FAILED_AUTH;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Invalid auth mode so lets fail all authentication attempts */
|
2018-11-28 12:16:01 +08:00
|
|
|
return LCBA_FAILED_AUTH;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Rewrite WSI_TOKEN_HTTP_AUTHORIZATION so it is just the
|
|
|
|
* authorized username
|
|
|
|
*/
|
|
|
|
|
|
|
|
*pcolon = '\0';
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->http.ah->frags[fi].len = (uint16_t)lws_ptr_diff_size_t(pcolon, &plain[0]);
|
2018-11-28 12:16:01 +08:00
|
|
|
pcolon = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_AUTHORIZATION);
|
2020-12-12 06:21:40 +00:00
|
|
|
strncpy(pcolon, plain, (unsigned int)(ml - 1));
|
2018-11-28 12:16:01 +08:00
|
|
|
pcolon[ml - 1] = '\0';
|
|
|
|
lwsl_info("%s: basic auth accepted for %s\n", __func__,
|
|
|
|
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_AUTHORIZATION));
|
|
|
|
|
|
|
|
return LCBA_CONTINUE;
|
2019-08-18 10:35:43 +01:00
|
|
|
#else
|
2022-02-13 09:17:27 +00:00
|
|
|
if (!basic_auth_login_file && auth_mode == LWSAUTHM_DEFAULT)
|
|
|
|
return LCBA_CONTINUE;
|
2019-08-18 10:35:43 +01:00
|
|
|
return LCBA_FAILED_AUTH;
|
|
|
|
#endif
|
2018-11-28 12:16:01 +08:00
|
|
|
}
|
|
|
|
|
2020-02-28 09:29:25 +00:00
|
|
|
#endif
|
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY)
|
|
|
|
/*
|
|
|
|
* Set up an onward http proxy connection according to the mount this
|
|
|
|
* uri falls under. Notice this can also be starting the proxying of what was
|
|
|
|
* originally an incoming h1 upgrade, or an h2 ws "upgrade".
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
|
|
|
|
char *uri_ptr, char ws)
|
|
|
|
{
|
2021-12-13 18:51:22 +03:00
|
|
|
char ads[96], host[96], *pcolon, *pslash, unix_skt = 0;
|
2019-03-19 11:53:57 +08:00
|
|
|
struct lws_client_connect_info i;
|
|
|
|
struct lws *cwsi;
|
|
|
|
int n, na;
|
2022-02-07 13:35:23 +00:00
|
|
|
unsigned int max_http_header_data = wsi->a.context->max_http_header_data > 256 ?
|
|
|
|
wsi->a.context->max_http_header_data : 256;
|
|
|
|
char *rpath = NULL;
|
2019-03-19 11:53:57 +08:00
|
|
|
|
2020-03-06 15:22:36 +00:00
|
|
|
#if defined(LWS_ROLE_WS)
|
2019-03-19 11:53:57 +08:00
|
|
|
if (ws)
|
|
|
|
/*
|
|
|
|
* Neither our inbound ws upgrade request side, nor our onward
|
|
|
|
* ws client connection on our side can bind to the actual
|
|
|
|
* protocol that only the remote inbound side and the remote
|
|
|
|
* onward side understand.
|
|
|
|
*
|
|
|
|
* Instead these are both bound to our built-in "lws-ws-proxy"
|
|
|
|
* protocol, which understands how to proxy between the two
|
|
|
|
* sides.
|
|
|
|
*
|
|
|
|
* We bind the parent, inbound part here and our side of the
|
|
|
|
* onward client connection is bound to the same handler using
|
|
|
|
* the .local_protocol_name.
|
|
|
|
*/
|
|
|
|
lws_bind_protocol(wsi, &lws_ws_proxy, __func__);
|
2020-03-06 15:22:36 +00:00
|
|
|
#endif
|
2019-03-19 11:53:57 +08:00
|
|
|
memset(&i, 0, sizeof(i));
|
|
|
|
i.context = lws_get_context(wsi);
|
|
|
|
|
|
|
|
if (hit->origin[0] == '+')
|
|
|
|
unix_skt = 1;
|
|
|
|
|
|
|
|
pcolon = strchr(hit->origin, ':');
|
|
|
|
pslash = strchr(hit->origin, '/');
|
|
|
|
if (!pslash) {
|
|
|
|
lwsl_err("Proxy mount origin '%s' must have /\n", hit->origin);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unix_skt) {
|
|
|
|
if (!pcolon) {
|
|
|
|
lwsl_err("Proxy mount origin for unix skt must "
|
|
|
|
"have address delimited by :\n");
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
n = lws_ptr_diff(pcolon, hit->origin);
|
|
|
|
pslash = pcolon;
|
|
|
|
} else {
|
|
|
|
if (pcolon > pslash)
|
|
|
|
pcolon = NULL;
|
|
|
|
|
|
|
|
if (pcolon)
|
|
|
|
n = (int)(pcolon - hit->origin);
|
|
|
|
else
|
|
|
|
n = (int)(pslash - hit->origin);
|
|
|
|
|
|
|
|
if (n >= (int)sizeof(ads) - 2)
|
|
|
|
n = sizeof(ads) - 2;
|
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
memcpy(ads, hit->origin, (unsigned int)n);
|
2019-03-19 11:53:57 +08:00
|
|
|
ads[n] = '\0';
|
|
|
|
|
|
|
|
i.address = ads;
|
|
|
|
i.port = 80;
|
|
|
|
if (hit->origin_protocol == LWSMPRO_HTTPS) {
|
|
|
|
i.port = 443;
|
|
|
|
i.ssl_connection = 1;
|
|
|
|
}
|
|
|
|
if (pcolon)
|
|
|
|
i.port = atoi(pcolon + 1);
|
|
|
|
|
2022-02-07 13:35:23 +00:00
|
|
|
rpath = lws_malloc(max_http_header_data, __func__);
|
|
|
|
if (!rpath)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* rpath needs cleaning after this... ---> */
|
|
|
|
|
2021-12-13 18:51:22 +03:00
|
|
|
n = lws_snprintf(rpath, max_http_header_data - 1, "/%s/%s",
|
2021-01-27 15:14:03 +00:00
|
|
|
pslash + 1, uri_ptr + hit->mountpoint_len) - 1;
|
2019-03-19 11:53:57 +08:00
|
|
|
lws_clean_url(rpath);
|
2021-01-27 15:14:03 +00:00
|
|
|
n = (int)strlen(rpath);
|
|
|
|
if (n && rpath[n - 1] == '/')
|
|
|
|
n--;
|
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
na = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_URI_ARGS);
|
|
|
|
if (na) {
|
2019-10-26 05:31:01 +01:00
|
|
|
char *p;
|
2021-01-27 15:14:03 +00:00
|
|
|
int budg;
|
2019-10-26 05:31:01 +01:00
|
|
|
|
|
|
|
if (!n) /* don't start with the ?... use the first / if so */
|
|
|
|
n++;
|
|
|
|
|
|
|
|
p = rpath + n;
|
2019-03-19 11:53:57 +08:00
|
|
|
|
2021-12-13 18:51:22 +03:00
|
|
|
if (na >= (int)max_http_header_data - n - 2) {
|
2019-03-19 11:53:57 +08:00
|
|
|
lwsl_info("%s: query string %d longer "
|
|
|
|
"than we can handle\n", __func__,
|
|
|
|
na);
|
2022-02-07 13:35:23 +00:00
|
|
|
lws_free(rpath);
|
2019-03-19 11:53:57 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*p++ = '?';
|
2021-01-27 15:14:03 +00:00
|
|
|
budg = lws_hdr_copy(wsi, p,
|
2021-12-13 18:51:22 +03:00
|
|
|
(int)(&rpath[max_http_header_data - 1] - p),
|
2021-01-27 15:14:03 +00:00
|
|
|
WSI_TOKEN_HTTP_URI_ARGS);
|
|
|
|
if (budg > 0)
|
|
|
|
p += budg;
|
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
*p = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
i.path = rpath;
|
2021-01-27 15:14:03 +00:00
|
|
|
lwsl_notice("%s: proxied path '%s'\n", __func__, i.path);
|
2019-04-05 21:13:59 +08:00
|
|
|
|
|
|
|
/* incoming may be h1 or h2... if he sends h1 HOST, use that
|
|
|
|
* directly, otherwise we must convert h2 :authority to h1
|
|
|
|
* host */
|
|
|
|
|
2022-09-18 06:01:00 +01:00
|
|
|
#if 0
|
2019-04-05 21:13:59 +08:00
|
|
|
i.host = NULL;
|
2020-02-28 10:31:04 +00:00
|
|
|
#if defined(LWS_ROLE_H2)
|
2019-04-05 21:13:59 +08:00
|
|
|
n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY);
|
|
|
|
if (n > 0)
|
|
|
|
i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY);
|
2020-02-28 10:31:04 +00:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2019-04-05 21:13:59 +08:00
|
|
|
n = lws_hdr_total_length(wsi, WSI_TOKEN_HOST);
|
2022-02-07 13:35:23 +00:00
|
|
|
if (n > 0)
|
2019-04-05 21:13:59 +08:00
|
|
|
i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST);
|
|
|
|
}
|
2022-09-18 06:01:00 +01:00
|
|
|
#endif
|
|
|
|
i.host = i.address;
|
2019-04-05 21:13:59 +08:00
|
|
|
|
|
|
|
#if 0
|
2019-03-19 11:53:57 +08:00
|
|
|
if (i.address[0] != '+' ||
|
|
|
|
!lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST))
|
|
|
|
i.host = i.address;
|
|
|
|
else
|
|
|
|
i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST);
|
2019-04-05 21:13:59 +08:00
|
|
|
#endif
|
2019-03-19 11:53:57 +08:00
|
|
|
i.origin = NULL;
|
2019-03-22 06:22:40 +08:00
|
|
|
if (!ws) {
|
|
|
|
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI)
|
|
|
|
#if defined(LWS_WITH_HTTP2)
|
|
|
|
|| (
|
|
|
|
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
|
2020-01-02 08:32:23 +00:00
|
|
|
!strcmp(lws_hdr_simple_ptr(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_METHOD), "post")
|
2019-03-22 06:22:40 +08:00
|
|
|
)
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
i.method = "POST";
|
2021-11-29 17:26:48 +03:00
|
|
|
else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PUT_URI)
|
|
|
|
#if defined(LWS_WITH_HTTP2)
|
|
|
|
|| (
|
|
|
|
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
|
|
|
|
!strcmp(lws_hdr_simple_ptr(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_METHOD), "put")
|
|
|
|
)
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
i.method = "PUT";
|
|
|
|
else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PATCH_URI)
|
|
|
|
#if defined(LWS_WITH_HTTP2)
|
|
|
|
|| (
|
|
|
|
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
|
|
|
|
!strcmp(lws_hdr_simple_ptr(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_METHOD), "patch")
|
|
|
|
)
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
i.method = "PATCH";
|
|
|
|
else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_DELETE_URI)
|
|
|
|
#if defined(LWS_WITH_HTTP2)
|
|
|
|
|| (
|
|
|
|
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
|
|
|
|
!strcmp(lws_hdr_simple_ptr(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_METHOD), "delete")
|
|
|
|
)
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
i.method = "DELETE";
|
2019-03-22 06:22:40 +08:00
|
|
|
else
|
|
|
|
i.method = "GET";
|
|
|
|
}
|
2019-03-19 11:53:57 +08:00
|
|
|
|
2019-04-05 21:13:59 +08:00
|
|
|
if (i.host)
|
|
|
|
lws_snprintf(host, sizeof(host), "%s:%u", i.host,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->listen_port);
|
2019-04-05 21:13:59 +08:00
|
|
|
else
|
|
|
|
lws_snprintf(host, sizeof(host), "%s:%d", i.address, i.port);
|
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
i.host = host;
|
|
|
|
|
|
|
|
i.alpn = "http/1.1";
|
|
|
|
i.parent_wsi = wsi;
|
|
|
|
i.pwsi = &cwsi;
|
2020-03-06 15:22:36 +00:00
|
|
|
#if defined(LWS_ROLE_WS)
|
2019-03-19 11:53:57 +08:00
|
|
|
i.protocol = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);
|
|
|
|
if (ws)
|
|
|
|
i.local_protocol_name = "lws-ws-proxy";
|
2020-03-06 15:22:36 +00:00
|
|
|
#endif
|
2019-03-19 11:53:57 +08:00
|
|
|
|
|
|
|
// i.uri_replace_from = hit->origin;
|
|
|
|
// i.uri_replace_to = hit->mountpoint;
|
|
|
|
|
|
|
|
lwsl_info("proxying to %s port %d url %s, ssl %d, from %s, to %s\n",
|
|
|
|
i.address, i.port, i.path, i.ssl_connection,
|
|
|
|
i.uri_replace_from, i.uri_replace_to);
|
|
|
|
|
|
|
|
if (!lws_client_connect_via_info(&i)) {
|
|
|
|
lwsl_err("proxy connect fail\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ... we can't do the proxy action, but we can
|
|
|
|
* cleanly return him a 503 and a description
|
|
|
|
*/
|
|
|
|
|
|
|
|
lws_return_http_status(wsi,
|
|
|
|
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
|
|
|
"<h1>Service Temporarily Unavailable</h1>"
|
|
|
|
"The server is temporarily unable to service "
|
|
|
|
"your request due to maintenance downtime or "
|
|
|
|
"capacity problems. Please try again later.");
|
2022-02-07 13:35:23 +00:00
|
|
|
lws_free(rpath);
|
2019-03-19 11:53:57 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2022-02-07 13:35:23 +00:00
|
|
|
lws_free(rpath);
|
2019-03-19 11:53:57 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: setting proxy clientside on %s (parent %s)\n",
|
|
|
|
__func__, lws_wsi_tag(cwsi), lws_wsi_tag(lws_get_parent(cwsi)));
|
2019-03-19 11:53:57 +08:00
|
|
|
|
|
|
|
cwsi->http.proxy_clientside = 1;
|
|
|
|
if (ws) {
|
|
|
|
wsi->proxied_ws_parent = 1;
|
|
|
|
cwsi->h1_ws_proxied = 1;
|
|
|
|
if (i.protocol) {
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_debug("%s: (requesting '%s')\n",
|
|
|
|
__func__, i.protocol);
|
2019-03-19 11:53:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-01-10 11:03:00 +00:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
static const char * const oprot[] = {
|
|
|
|
"http://", "https://"
|
|
|
|
};
|
|
|
|
|
2020-01-10 11:03:00 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
lws_http_redirect_hit(struct lws_context_per_thread *pt, struct lws *wsi,
|
|
|
|
const struct lws_http_mount *hit, char *uri_ptr,
|
|
|
|
int uri_len, int *h)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
*h = 0;
|
|
|
|
s = uri_ptr + hit->mountpoint_len;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)) {
|
|
|
|
unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
*end = p + wsi->a.context->pt_serv_buf_size -
|
2020-01-10 11:03:00 +00:00
|
|
|
LWS_PRE - 512;
|
|
|
|
|
|
|
|
*h = 1;
|
|
|
|
|
|
|
|
lwsl_info("Doing 301 '%s' org %s\n", s, hit->origin);
|
|
|
|
|
|
|
|
/* > at start indicates deal with by redirect */
|
|
|
|
if (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
|
|
|
|
hit->origin_protocol == LWSMPRO_REDIR_HTTPS)
|
|
|
|
n = lws_snprintf((char *)end, 256, "%s%s",
|
|
|
|
oprot[hit->origin_protocol & 1],
|
|
|
|
hit->origin);
|
|
|
|
else {
|
|
|
|
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
|
2020-02-28 10:31:04 +00:00
|
|
|
#if defined(LWS_ROLE_H2)
|
2020-01-10 11:03:00 +00:00
|
|
|
if (!lws_hdr_total_length(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_AUTHORITY))
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
2020-01-10 11:03:00 +00:00
|
|
|
goto bail_nuke_ah;
|
2020-02-28 10:31:04 +00:00
|
|
|
#if defined(LWS_ROLE_H2)
|
2020-01-10 11:03:00 +00:00
|
|
|
n = lws_snprintf((char *)end, 256,
|
|
|
|
"%s%s%s/", oprot[!!lws_is_ssl(wsi)],
|
|
|
|
lws_hdr_simple_ptr(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_AUTHORITY),
|
|
|
|
uri_ptr);
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
2020-01-10 11:03:00 +00:00
|
|
|
} else
|
|
|
|
n = lws_snprintf((char *)end, 256,
|
|
|
|
"%s%s%s/", oprot[!!lws_is_ssl(wsi)],
|
|
|
|
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
|
|
|
|
uri_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
lws_clean_url((char *)end);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bail_nuke_ah:
|
|
|
|
lws_header_table_detach(wsi, 1);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-09-06 09:30:32 +08:00
|
|
|
int
|
|
|
|
lws_http_action(struct lws *wsi)
|
|
|
|
{
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
2020-01-10 11:03:00 +00:00
|
|
|
int uri_len = 0, meth, m, http_version_len, ha;
|
2018-11-23 08:47:56 +08:00
|
|
|
const struct lws_http_mount *hit = NULL;
|
2017-09-06 09:30:32 +08:00
|
|
|
enum http_version request_version;
|
|
|
|
struct lws_process_html_args args;
|
2018-11-23 08:47:56 +08:00
|
|
|
enum http_conn_type conn_type;
|
|
|
|
char content_length_str[32];
|
2018-10-26 16:14:30 +08:00
|
|
|
char http_version_str[12];
|
2018-11-23 08:47:56 +08:00
|
|
|
char http_conn_str[25];
|
2020-08-18 09:34:50 +01:00
|
|
|
char *uri_ptr = NULL;
|
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
|
|
|
char *s;
|
|
|
|
#endif
|
2018-11-23 08:47:56 +08:00
|
|
|
unsigned int n;
|
2017-09-06 09:30:32 +08:00
|
|
|
|
|
|
|
meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
|
2018-08-16 19:10:32 +08:00
|
|
|
if (meth < 0 || meth >= (int)LWS_ARRAY_SIZE(method_names))
|
2017-09-06 09:30:32 +08:00
|
|
|
goto bail_nuke_ah;
|
2016-04-15 12:00:23 +08:00
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
lws_metrics_tag_wsi_add(wsi, "vh", wsi->a.vhost->name);
|
|
|
|
lws_metrics_tag_wsi_add(wsi, "meth", method_names[meth]);
|
|
|
|
|
2016-04-02 07:36:17 +08:00
|
|
|
/* we insist on absolute paths */
|
|
|
|
|
2017-07-19 14:19:03 +08:00
|
|
|
if (!uri_ptr || uri_ptr[0] != '/') {
|
2016-04-02 07:36:17 +08:00
|
|
|
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
|
|
|
|
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
}
|
|
|
|
|
2017-10-16 12:52:32 +08:00
|
|
|
lwsl_info("Method: '%s' (%d), request for '%s'\n", method_names[meth],
|
|
|
|
meth, uri_ptr);
|
2017-09-06 09:30:32 +08:00
|
|
|
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (wsi->role_ops &&
|
|
|
|
lws_rops_fidx(wsi->role_ops, LWS_ROPS_check_upgrades))
|
|
|
|
switch (lws_rops_func_fidx(wsi->role_ops,
|
|
|
|
LWS_ROPS_check_upgrades).
|
|
|
|
check_upgrades(wsi)) {
|
2018-04-11 13:39:42 +08:00
|
|
|
case LWS_UPG_RET_DONE:
|
|
|
|
return 0;
|
|
|
|
case LWS_UPG_RET_CONTINUE:
|
|
|
|
break;
|
|
|
|
case LWS_UPG_RET_BAIL:
|
|
|
|
goto bail_nuke_ah;
|
2018-03-11 11:26:06 +08:00
|
|
|
}
|
|
|
|
|
2017-09-06 09:30:32 +08:00
|
|
|
if (lws_ensure_user_space(wsi))
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
/* HTTP header had a content length? */
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.rx_content_length = 0;
|
2018-07-21 10:26:13 +08:00
|
|
|
wsi->http.content_length_explicitly_zero = 0;
|
2020-02-28 10:31:04 +00:00
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)
|
|
|
|
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
|
|
|
|
||
|
2018-11-07 17:02:09 +08:00
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
|
2020-02-28 10:31:04 +00:00
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI)
|
|
|
|
#endif
|
|
|
|
)
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.rx_content_length = 100 * 1024 * 1024;
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2018-11-07 17:02:09 +08:00
|
|
|
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) > 0) {
|
2019-07-05 06:07:03 +01:00
|
|
|
wsi->http.rx_content_remain = wsi->http.rx_content_length =
|
2020-12-12 06:21:40 +00:00
|
|
|
(lws_filepos_t)atoll(content_length_str);
|
2018-11-07 17:02:09 +08:00
|
|
|
if (!wsi->http.rx_content_length) {
|
|
|
|
wsi->http.content_length_explicitly_zero = 1;
|
|
|
|
lwsl_debug("%s: explicit 0 content-length\n", __func__);
|
2018-07-21 10:26:13 +08:00
|
|
|
}
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->mux_substream) {
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.request_version = HTTP_VERSION_2;
|
2016-04-10 09:33:54 +08:00
|
|
|
} 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);
|
2018-11-07 17:02:09 +08:00
|
|
|
if (http_version_len > 7 &&
|
|
|
|
lws_hdr_copy(wsi, http_version_str,
|
|
|
|
sizeof(http_version_str) - 1,
|
|
|
|
WSI_TOKEN_HTTP) > 0 &&
|
|
|
|
http_version_str[5] == '1' && http_version_str[7] == '1')
|
|
|
|
request_version = HTTP_VERSION_1_1;
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.request_version = request_version;
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2016-04-10 09:33:54 +08:00
|
|
|
/* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */
|
|
|
|
if (request_version == HTTP_VERSION_1_1)
|
2018-09-02 14:35:37 +08:00
|
|
|
conn_type = HTTP_CONNECTION_KEEP_ALIVE;
|
2014-10-08 12:00:53 +08:00
|
|
|
else
|
2018-09-02 14:35:37 +08:00
|
|
|
conn_type = HTTP_CONNECTION_CLOSE;
|
2016-04-10 09:33:54 +08:00
|
|
|
|
|
|
|
/* Override default if http "Connection:" header: */
|
2018-10-26 16:14:30 +08:00
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION) &&
|
|
|
|
lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1,
|
|
|
|
WSI_TOKEN_CONNECTION) > 0) {
|
2016-04-10 09:33:54 +08:00
|
|
|
http_conn_str[sizeof(http_conn_str) - 1] = '\0';
|
|
|
|
if (!strcasecmp(http_conn_str, "keep-alive"))
|
2018-09-02 14:35:37 +08:00
|
|
|
conn_type = HTTP_CONNECTION_KEEP_ALIVE;
|
2016-04-10 09:33:54 +08:00
|
|
|
else
|
|
|
|
if (!strcasecmp(http_conn_str, "close"))
|
2018-09-02 14:35:37 +08:00
|
|
|
conn_type = HTTP_CONNECTION_CLOSE;
|
2016-04-10 09:33:54 +08:00
|
|
|
}
|
2018-09-02 14:35:37 +08:00
|
|
|
wsi->http.conn_type = conn_type;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)wsi->a.protocol->callback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,
|
|
|
|
wsi->user_space, uri_ptr, (unsigned int)uri_len);
|
ah owns rxbuf
This is intended to solve a longstanding problem with the
relationship between http/1.1 keep-alive and the service
loop.
Ah now contain an rx buffer which is used during header
processing, and the ah may not be detached from the wsi
until the rx buffer is exhausted.
Having the rx buffer in the ah means we can delay using the
rx until a later service loop.
Ah which have pending rx force POLLIN service on the wsi
they are attached to automatically, so we can interleave
general service / connections with draining each ah rx
buffer.
The possible http/1.1 situations and their dispositions are:
1) exactly one set of http headers come. After processing,
the ah is detached since no pending rx left. If more
headers come later, a fresh ah is aqcuired when available
and the rx flow control blocks the read until then.
2) more that one whole set of headers come and we remain in
http mode (no upgrade). The ah is left attached and
returns to the service loop after the first set of headers.
We will get forced service due to the ah having pending
content (respecting flowcontrol) and process the pending
rx in the ah. If we use it all up, we will detach the
ah.
3) one set of http headers come with ws traffic appended.
We service the headers, do the upgrade, and keep the ah
until the remaining ws content is used. When we
exhausted the ws traffix in the ah rx buffer, we
detach the ah.
Since there can be any amount of http/1.1 pipelining on a
connection, and each may be expensive to service, it's now
enforced there is a return to the service loop after each
header set is serviced on a connection.
When I added the forced service for ah with pending buffering,
I added support for it to the windows plat code. However this
is untested.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-15 12:37:04 +08:00
|
|
|
if (n) {
|
|
|
|
lwsl_info("LWS_CALLBACK_HTTP closing\n");
|
2014-10-08 12:00:53 +08:00
|
|
|
|
ah owns rxbuf
This is intended to solve a longstanding problem with the
relationship between http/1.1 keep-alive and the service
loop.
Ah now contain an rx buffer which is used during header
processing, and the ah may not be detached from the wsi
until the rx buffer is exhausted.
Having the rx buffer in the ah means we can delay using the
rx until a later service loop.
Ah which have pending rx force POLLIN service on the wsi
they are attached to automatically, so we can interleave
general service / connections with draining each ah rx
buffer.
The possible http/1.1 situations and their dispositions are:
1) exactly one set of http headers come. After processing,
the ah is detached since no pending rx left. If more
headers come later, a fresh ah is aqcuired when available
and the rx flow control blocks the read until then.
2) more that one whole set of headers come and we remain in
http mode (no upgrade). The ah is left attached and
returns to the service loop after the first set of headers.
We will get forced service due to the ah having pending
content (respecting flowcontrol) and process the pending
rx in the ah. If we use it all up, we will detach the
ah.
3) one set of http headers come with ws traffic appended.
We service the headers, do the upgrade, and keep the ah
until the remaining ws content is used. When we
exhausted the ws traffix in the ah rx buffer, we
detach the ah.
Since there can be any amount of http/1.1 pipelining on a
connection, and each may be expensive to service, it's now
enforced there is a return to the service loop after each
header set is serviced on a connection.
When I added the forced service for ah with pending buffering,
I added support for it to the windows plat code. However this
is untested.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-15 12:37:04 +08:00
|
|
|
return 1;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
2016-02-06 08:44:34 +08:00
|
|
|
/*
|
ah owns rxbuf
This is intended to solve a longstanding problem with the
relationship between http/1.1 keep-alive and the service
loop.
Ah now contain an rx buffer which is used during header
processing, and the ah may not be detached from the wsi
until the rx buffer is exhausted.
Having the rx buffer in the ah means we can delay using the
rx until a later service loop.
Ah which have pending rx force POLLIN service on the wsi
they are attached to automatically, so we can interleave
general service / connections with draining each ah rx
buffer.
The possible http/1.1 situations and their dispositions are:
1) exactly one set of http headers come. After processing,
the ah is detached since no pending rx left. If more
headers come later, a fresh ah is aqcuired when available
and the rx flow control blocks the read until then.
2) more that one whole set of headers come and we remain in
http mode (no upgrade). The ah is left attached and
returns to the service loop after the first set of headers.
We will get forced service due to the ah having pending
content (respecting flowcontrol) and process the pending
rx in the ah. If we use it all up, we will detach the
ah.
3) one set of http headers come with ws traffic appended.
We service the headers, do the upgrade, and keep the ah
until the remaining ws content is used. When we
exhausted the ws traffix in the ah rx buffer, we
detach the ah.
Since there can be any amount of http/1.1 pipelining on a
connection, and each may be expensive to service, it's now
enforced there is a return to the service loop after each
header set is serviced on a connection.
When I added the forced service for ah with pending buffering,
I added support for it to the windows plat code. However this
is untested.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-15 12:37:04 +08:00
|
|
|
* if there is content supposed to be coming,
|
|
|
|
* put a timeout on it having arrived
|
2016-02-06 08:44:34 +08:00
|
|
|
*/
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_stream_immortal)
|
2019-09-13 10:33:24 +01:00
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)wsi->a.context->timeout_secs);
|
2020-11-20 18:01:12 +00:00
|
|
|
#if defined(LWS_WITH_TLS)
|
2018-05-01 12:41:42 +08:00
|
|
|
if (wsi->tls.redirect_to_https) {
|
2016-03-17 15:26:49 +08:00
|
|
|
/*
|
2020-11-20 18:01:12 +00:00
|
|
|
* We accepted http:// only so we could redirect to
|
2016-03-17 15:26:49 +08:00
|
|
|
* https://, so issue the redirect. Create the redirection
|
2020-11-20 18:01:12 +00:00
|
|
|
* URI from the host: header, and regenerate the path part from
|
|
|
|
* the parsed pieces
|
2016-03-17 15:26:49 +08:00
|
|
|
*/
|
|
|
|
unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
|
2020-11-20 18:01:12 +00:00
|
|
|
*end = p + wsi->a.context->pt_serv_buf_size -
|
|
|
|
LWS_PRE;
|
2016-03-17 15:26:49 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)lws_hdr_total_length(wsi, WSI_TOKEN_HOST);
|
2018-11-29 08:47:49 +08:00
|
|
|
if (!n || n > 128)
|
2016-03-17 15:26:49 +08:00
|
|
|
goto bail_nuke_ah;
|
2016-04-15 20:09:36 +08:00
|
|
|
|
2020-08-18 10:33:57 +01:00
|
|
|
if (!lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST))
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "https://");
|
2018-11-29 08:47:49 +08:00
|
|
|
memcpy(p, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST), n);
|
|
|
|
p += n;
|
|
|
|
*p++ = '/';
|
2020-11-20 18:01:12 +00:00
|
|
|
if (uri_len >= lws_ptr_diff(end, p))
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
|
|
|
|
if (uri_ptr[0])
|
|
|
|
p--;
|
2020-12-12 06:21:40 +00:00
|
|
|
memcpy(p, uri_ptr, (unsigned int)uri_len);
|
2020-11-20 18:01:12 +00:00
|
|
|
p += uri_len;
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
while (lws_hdr_copy_fragment(wsi, (char *)p + 1,
|
|
|
|
lws_ptr_diff(end, p) - 2,
|
2020-12-12 06:21:40 +00:00
|
|
|
WSI_TOKEN_HTTP_URI_ARGS, (int)n) > 0) {
|
2020-11-20 18:01:12 +00:00
|
|
|
*p = n ? '&' : '?';
|
|
|
|
p += strlen((char *)p);
|
|
|
|
if (p >= end - 2)
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)lws_ptr_diff(p, start);
|
2016-04-15 20:09:36 +08:00
|
|
|
|
2018-11-29 08:47:49 +08:00
|
|
|
p += LWS_PRE;
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
|
|
|
|
start, (int)n, &p, end);
|
2016-03-18 23:55:59 +08:00
|
|
|
if ((int)n < 0)
|
2016-03-17 15:26:49 +08:00
|
|
|
goto bail_nuke_ah;
|
|
|
|
|
|
|
|
return lws_http_transaction_completed(wsi);
|
|
|
|
}
|
2016-04-13 11:42:53 +08:00
|
|
|
#endif
|
2016-03-17 15:26:49 +08:00
|
|
|
|
2016-04-15 12:00:23 +08:00
|
|
|
#ifdef LWS_WITH_ACCESS_LOG
|
2018-08-14 08:00:25 +08:00
|
|
|
lws_prepare_access_log_info(wsi, uri_ptr, uri_len, meth);
|
2016-04-15 12:00:23 +08:00
|
|
|
#endif
|
|
|
|
|
2016-03-28 10:10:43 +08:00
|
|
|
/* can we serve it from the mount list? */
|
|
|
|
|
2023-12-12 05:55:49 +00:00
|
|
|
wsi->mount_hit = 0;
|
2016-06-26 06:29:20 +08:00
|
|
|
hit = lws_find_mount(wsi, uri_ptr, uri_len);
|
|
|
|
if (!hit) {
|
|
|
|
/* deferred cleanup and reset to protocols[0] */
|
2016-04-08 13:25:34 +08:00
|
|
|
|
2016-06-26 06:29:20 +08:00
|
|
|
lwsl_info("no hit\n");
|
2016-04-08 18:30:45 +08:00
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[0],
|
2018-11-23 08:47:56 +08:00
|
|
|
"no mount hit"))
|
2016-06-26 06:29:20 +08:00
|
|
|
return 1;
|
2016-05-19 15:28:31 +08:00
|
|
|
|
2018-05-04 12:05:56 +08:00
|
|
|
lwsi_set_state(wsi, LRS_DOING_TRANSACTION);
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->user_space, uri_ptr, (unsigned int)uri_len);
|
2016-05-19 15:28:31 +08:00
|
|
|
|
2016-06-26 06:29:20 +08:00
|
|
|
goto after;
|
|
|
|
}
|
2016-05-19 15:28:31 +08:00
|
|
|
|
2023-12-12 05:55:49 +00:00
|
|
|
wsi->mount_hit = 1;
|
|
|
|
|
2020-08-18 09:34:50 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2016-06-26 06:29:20 +08:00
|
|
|
s = uri_ptr + hit->mountpoint_len;
|
2020-08-18 09:34:50 +01:00
|
|
|
#endif
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)lws_http_redirect_hit(pt, wsi, hit, uri_ptr, uri_len, &ha);
|
2020-01-10 11:03:00 +00:00
|
|
|
if (ha)
|
2020-12-12 06:21:40 +00:00
|
|
|
return (int)n;
|
2016-06-26 06:29:20 +08:00
|
|
|
|
2020-02-28 09:29:25 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_BASIC_AUTH)
|
|
|
|
|
2016-12-03 15:13:15 +08:00
|
|
|
/* basic auth? */
|
|
|
|
|
2019-12-12 18:45:00 +00:00
|
|
|
switch (lws_check_basic_auth(wsi, hit->basic_auth_login_file,
|
|
|
|
hit->auth_mask & AUTH_MODE_MASK)) {
|
2018-11-28 12:16:01 +08:00
|
|
|
case LCBA_CONTINUE:
|
|
|
|
break;
|
|
|
|
case LCBA_FAILED_AUTH:
|
|
|
|
return lws_unauthorised_basic_auth(wsi);
|
|
|
|
case LCBA_END_TRANSACTION:
|
|
|
|
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
|
|
|
|
return lws_http_transaction_completed(wsi);
|
2016-12-03 15:13:15 +08:00
|
|
|
}
|
2020-02-28 09:29:25 +00:00
|
|
|
#endif
|
2016-12-03 15:13:15 +08:00
|
|
|
|
2017-06-12 13:36:24 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_PROXY)
|
|
|
|
/*
|
|
|
|
* The mount is a reverse proxy?
|
|
|
|
*/
|
|
|
|
|
2019-03-22 06:22:40 +08:00
|
|
|
// if (hit)
|
2018-09-04 08:06:46 +08:00
|
|
|
// lwsl_notice("%s: origin_protocol: %d\n", __func__, hit->origin_protocol);
|
2019-03-22 06:22:40 +08:00
|
|
|
//else
|
|
|
|
// lwsl_notice("%s: no hit\n", __func__);
|
2018-09-04 08:06:46 +08:00
|
|
|
|
2017-06-12 13:36:24 +08:00
|
|
|
if (hit->origin_protocol == LWSMPRO_HTTPS ||
|
2019-03-22 06:22:40 +08:00
|
|
|
hit->origin_protocol == LWSMPRO_HTTP) {
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)lws_http_proxy_start(wsi, hit, uri_ptr, 0);
|
2019-04-05 21:13:59 +08:00
|
|
|
// lwsl_notice("proxy start says %d\n", n);
|
2019-03-22 06:22:40 +08:00
|
|
|
if (n)
|
2020-12-12 06:21:40 +00:00
|
|
|
return (int)n;
|
2019-03-22 06:22:40 +08:00
|
|
|
|
|
|
|
goto deal_body;
|
|
|
|
}
|
2017-06-12 13:36:24 +08:00
|
|
|
#endif
|
|
|
|
|
2016-06-26 06:29:20 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
pp = lws_vhost_name_to_protocol(wsi->a.vhost, name);
|
2016-06-26 06:29:20 +08:00
|
|
|
if (!pp) {
|
|
|
|
lwsl_err("Unable to find plugin '%s'\n",
|
2022-06-14 05:33:41 +01:00
|
|
|
name);
|
2016-06-26 06:29:20 +08:00
|
|
|
return 1;
|
2016-04-13 11:49:07 +08:00
|
|
|
}
|
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
if (lws_bind_protocol(wsi, pp, "http action CALLBACK bind"))
|
2016-06-26 06:29:20 +08:00
|
|
|
return 1;
|
2016-05-09 09:37:01 +08:00
|
|
|
|
2019-08-30 13:08:09 +01:00
|
|
|
lwsl_debug("%s: %s, checking access rights for mask 0x%x\n",
|
2019-04-05 21:13:59 +08:00
|
|
|
__func__, hit->origin, hit->auth_mask);
|
|
|
|
|
2016-11-26 20:46:04 +08:00
|
|
|
args.p = uri_ptr;
|
|
|
|
args.len = uri_len;
|
2019-12-12 18:45:00 +00:00
|
|
|
args.max_len = hit->auth_mask & ~AUTH_MODE_MASK;
|
2016-11-26 20:46:04 +08:00
|
|
|
args.final = 0; /* used to signal callback dealt with it */
|
2018-01-14 20:09:41 +08:00
|
|
|
args.chunked = 0;
|
2016-11-26 20:46:04 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)wsi->a.protocol->callback(wsi,
|
2017-11-06 10:05:04 +08:00
|
|
|
LWS_CALLBACK_CHECK_ACCESS_RIGHTS,
|
2016-11-26 20:46:04 +08:00
|
|
|
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;
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (hit->cgienv && wsi->a.protocol->callback(wsi,
|
2016-06-26 06:29:20 +08:00
|
|
|
LWS_CALLBACK_HTTP_PMO,
|
|
|
|
wsi->user_space, (void *)hit->cgienv, 0))
|
|
|
|
return 1;
|
2016-05-09 09:37:01 +08:00
|
|
|
|
2016-06-26 06:29:20 +08:00
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
|
2016-06-26 06:29:20 +08:00
|
|
|
wsi->user_space,
|
|
|
|
uri_ptr + hit->mountpoint_len,
|
2020-12-12 06:21:40 +00:00
|
|
|
(unsigned int)uri_len - hit->mountpoint_len);
|
2016-05-09 09:37:01 +08:00
|
|
|
goto after;
|
|
|
|
}
|
2016-06-26 06:29:20 +08:00
|
|
|
}
|
2016-05-09 09:37:01 +08:00
|
|
|
|
2016-04-13 11:49:07 +08:00
|
|
|
#ifdef LWS_WITH_CGI
|
2016-06-26 06:29:20 +08:00
|
|
|
/* did we hit something with a cgi:// origin? */
|
|
|
|
if (hit->origin_protocol == LWSMPRO_CGI) {
|
|
|
|
const char *cmd[] = {
|
|
|
|
NULL, /* replace with cgi path */
|
|
|
|
NULL
|
|
|
|
};
|
2016-04-13 11:49:07 +08:00
|
|
|
|
2016-06-26 06:29:20 +08:00
|
|
|
lwsl_debug("%s: cgi\n", __func__);
|
|
|
|
cmd[0] = hit->origin;
|
2016-04-13 11:49:07 +08:00
|
|
|
|
2016-06-26 06:29:20 +08:00
|
|
|
n = 5;
|
|
|
|
if (hit->cgi_timeout)
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)hit->cgi_timeout;
|
2016-06-26 06:29:20 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)lws_cgi(wsi, cmd, hit->mountpoint_len, (int)n,
|
2016-06-26 06:29:20 +08:00
|
|
|
hit->cgienv);
|
|
|
|
if (n) {
|
2017-02-05 22:07:34 +08:00
|
|
|
lwsl_err("%s: cgi failed\n", __func__);
|
2016-06-26 06:29:20 +08:00
|
|
|
return -1;
|
2016-04-13 11:49:07 +08:00
|
|
|
}
|
|
|
|
|
2016-06-26 06:29:20 +08:00
|
|
|
goto deal_body;
|
|
|
|
}
|
|
|
|
#endif
|
2016-04-13 11:49:07 +08:00
|
|
|
|
2020-08-18 09:34:50 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)(uri_len - lws_ptr_diff(s, uri_ptr));
|
2016-06-26 06:29:20 +08:00
|
|
|
if (s[0] == '\0' || (n == 1 && s[n - 1] == '/'))
|
|
|
|
s = (char *)hit->def;
|
|
|
|
if (!s)
|
|
|
|
s = "index.html";
|
2020-08-18 09:34:50 +01:00
|
|
|
#endif
|
2016-05-19 15:28:31 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->cache_secs = (unsigned int)hit->cache_max_age;
|
2016-06-26 06:29:20 +08:00
|
|
|
wsi->cache_reuse = hit->cache_reusable;
|
|
|
|
wsi->cache_revalidate = hit->cache_revalidate;
|
2021-12-07 14:20:47 +00:00
|
|
|
wsi->cache_no = hit->cache_no;
|
2016-06-26 06:29:20 +08:00
|
|
|
wsi->cache_intermediaries = hit->cache_intermediaries;
|
2016-05-09 09:37:01 +08:00
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2020-08-18 09:28:40 +01:00
|
|
|
m = 1;
|
2018-03-20 10:31:53 +08:00
|
|
|
if (hit->origin_protocol == LWSMPRO_FILE)
|
2018-07-16 09:34:39 +08:00
|
|
|
m = lws_http_serve(wsi, s, hit->origin, hit);
|
|
|
|
|
2020-01-14 10:06:16 +00:00
|
|
|
if (m > 0)
|
|
|
|
#endif
|
|
|
|
{
|
2024-10-31 15:18:11 +00:00
|
|
|
lwsl_notice("%s: hit->protocol %s\n", __func__, hit->protocol);
|
2016-06-26 06:29:20 +08:00
|
|
|
/*
|
2017-11-06 10:05:04 +08:00
|
|
|
* lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
|
2016-06-26 06:29:20 +08:00
|
|
|
*/
|
|
|
|
if (hit->protocol) {
|
2017-11-06 10:05:04 +08:00
|
|
|
const struct lws_protocols *pp =
|
|
|
|
lws_vhost_name_to_protocol(
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost, hit->protocol);
|
2024-10-31 15:18:11 +00:00
|
|
|
lwsl_notice("%s: pp %p\n", __func__, pp);
|
2020-08-18 10:31:35 +01:00
|
|
|
/* coverity */
|
|
|
|
if (!pp)
|
|
|
|
return 1;
|
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
lwsi_set_state(wsi, LRS_DOING_TRANSACTION);
|
|
|
|
|
|
|
|
if (lws_bind_protocol(wsi, pp, "http_action HTTP"))
|
2016-06-26 06:29:20 +08:00
|
|
|
return 1;
|
2016-05-09 09:37:01 +08:00
|
|
|
|
2018-07-16 09:34:39 +08:00
|
|
|
m = pp->callback(wsi, LWS_CALLBACK_HTTP,
|
2016-06-26 06:29:20 +08:00
|
|
|
wsi->user_space,
|
|
|
|
uri_ptr + hit->mountpoint_len,
|
2020-12-12 06:21:40 +00:00
|
|
|
(size_t)(uri_len - hit->mountpoint_len));
|
2016-06-26 06:29:20 +08:00
|
|
|
} else
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->user_space, uri_ptr, (size_t)uri_len);
|
2016-05-09 09:37:01 +08:00
|
|
|
}
|
2016-06-26 06:29:20 +08:00
|
|
|
|
2016-05-09 09:37:01 +08:00
|
|
|
after:
|
2018-07-16 09:34:39 +08:00
|
|
|
if (m) {
|
2016-02-25 20:27:10 +08:00
|
|
|
lwsl_info("LWS_CALLBACK_HTTP closing\n");
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2019-03-22 06:22:40 +08:00
|
|
|
#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
|
2016-04-13 11:42:53 +08:00
|
|
|
deal_body:
|
|
|
|
#endif
|
2015-12-14 08:52:03 +08:00
|
|
|
/*
|
2014-10-08 12:00:53 +08:00
|
|
|
* If we're not issuing a file, check for content_length or
|
|
|
|
* HTTP keep-alive. No keep-alive header allocation for
|
2015-12-14 08:52:03 +08:00
|
|
|
* ISSUING_FILE, as this uses HTTP/1.0.
|
|
|
|
*
|
2015-12-04 08:43:54 +08:00
|
|
|
* In any case, return 0 and let lws_read decide how to
|
2014-10-08 12:00:53 +08:00
|
|
|
* proceed based on state
|
|
|
|
*/
|
2020-01-02 08:32:23 +00:00
|
|
|
if (lwsi_state(wsi) == LRS_ISSUING_FILE)
|
|
|
|
return 0;
|
2018-07-21 10:26:13 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
/* Prepare to read body if we have a content length: */
|
|
|
|
lwsl_debug("wsi->http.rx_content_length %lld %d %d\n",
|
|
|
|
(long long)wsi->http.rx_content_length,
|
|
|
|
wsi->upgraded_to_http2, wsi->mux_substream);
|
2018-07-21 10:26:13 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
if (wsi->http.content_length_explicitly_zero &&
|
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
|
2018-07-21 10:26:13 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
/*
|
|
|
|
* POST with an explicit content-length of zero
|
|
|
|
*
|
|
|
|
* If we don't give the user code the empty HTTP_BODY callback,
|
|
|
|
* he may become confused to hear the HTTP_BODY_COMPLETION (due
|
|
|
|
* to, eg, instantiation of lws_spa never happened).
|
|
|
|
*
|
|
|
|
* HTTP_BODY_COMPLETION is responsible for sending the result
|
|
|
|
* status code and result body if any, and to do the transaction
|
|
|
|
* complete processing.
|
|
|
|
*/
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY,
|
2020-01-02 08:32:23 +00:00
|
|
|
wsi->user_space, NULL, 0))
|
|
|
|
return 1;
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY_COMPLETION,
|
2020-01-02 08:32:23 +00:00
|
|
|
wsi->user_space, NULL, 0))
|
|
|
|
return 1;
|
2018-07-21 10:26:13 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
if (wsi->http.rx_content_length <= 0)
|
|
|
|
return 0;
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
if (lwsi_state(wsi) != LRS_DISCARD_BODY) {
|
|
|
|
lwsi_set_state(wsi, LRS_BODY);
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: LRS_BODY state set (0x%x)\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), (int)wsi->wsistate);
|
2020-01-02 08:32:23 +00:00
|
|
|
}
|
|
|
|
wsi->http.rx_content_remain = wsi->http.rx_content_length;
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
/*
|
|
|
|
* At this point we have transitioned from deferred
|
|
|
|
* action to expecting BODY on the stream wsi, if it's
|
|
|
|
* in a bundle like h2. So if the stream wsi has its
|
|
|
|
* own buflist, we need to deal with that first.
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct lws_tokens ebuf;
|
|
|
|
int m;
|
|
|
|
|
|
|
|
ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist,
|
|
|
|
&ebuf.token);
|
|
|
|
if (!ebuf.len)
|
|
|
|
break;
|
|
|
|
|
|
|
|
lwsl_debug("%s: consuming %d\n", __func__, (int)ebuf.len);
|
2020-12-12 06:21:40 +00:00
|
|
|
m = lws_read_h1(wsi, ebuf.token, (lws_filepos_t)ebuf.len);
|
2020-01-02 08:32:23 +00:00
|
|
|
if (m < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (lws_buflist_aware_finished_consuming(wsi, &ebuf, m, 1,
|
|
|
|
__func__))
|
|
|
|
return -1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2014-10-08 12:00:53 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bail_nuke_ah:
|
2016-02-27 11:42:22 +08:00
|
|
|
lws_header_table_detach(wsi, 1);
|
2014-12-05 00:09:20 +01:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-11-13 09:33:13 +08:00
|
|
|
int
|
|
|
|
lws_confirm_host_header(struct lws *wsi)
|
|
|
|
{
|
|
|
|
struct lws_tokenize ts;
|
|
|
|
lws_tokenize_elem e;
|
2020-01-11 14:04:50 +00:00
|
|
|
int port = 80, n;
|
2018-11-13 09:33:13 +08:00
|
|
|
char buf[128];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* this vhost wants us to validate what the
|
|
|
|
* client sent against our vhost name
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
|
|
|
|
lwsl_info("%s: missing host on upgrade\n", __func__);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_TLS)
|
|
|
|
if (wsi->tls.ssl)
|
|
|
|
port = 443;
|
|
|
|
#endif
|
|
|
|
|
2020-01-11 14:04:50 +00:00
|
|
|
n = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_HOST);
|
|
|
|
if (n <= 0) {
|
2018-11-13 09:33:13 +08:00
|
|
|
lwsl_info("%s: missing or oversize host header\n", __func__);
|
|
|
|
return 1;
|
|
|
|
}
|
2020-12-12 06:21:40 +00:00
|
|
|
ts.len = (size_t)n;
|
2021-09-09 05:14:01 +01:00
|
|
|
lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_DOT_NONTERM /* server.com */|
|
|
|
|
LWS_TOKENIZE_F_NO_FLOATS /* 1.server.com */|
|
|
|
|
LWS_TOKENIZE_F_MINUS_NONTERM /* a-b.com */);
|
2018-11-13 09:33:13 +08:00
|
|
|
|
|
|
|
if (lws_tokenize(&ts) != LWS_TOKZE_TOKEN)
|
|
|
|
goto bad_format;
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (strncmp(ts.token, wsi->a.vhost->name, ts.token_len)) {
|
2020-12-12 06:21:40 +00:00
|
|
|
buf[(size_t)(ts.token - buf) + ts.token_len] = '\0';
|
2018-11-13 09:33:13 +08:00
|
|
|
lwsl_info("%s: '%s' in host hdr but vhost name %s\n",
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
__func__, ts.token, wsi->a.vhost->name);
|
2018-11-13 09:33:13 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
e = lws_tokenize(&ts);
|
|
|
|
if (e == LWS_TOKZE_DELIMITER && ts.token[0] == ':') {
|
|
|
|
if (lws_tokenize(&ts) != LWS_TOKZE_INTEGER)
|
|
|
|
goto bad_format;
|
|
|
|
else
|
|
|
|
port = atoi(ts.token);
|
|
|
|
} else
|
|
|
|
if (e != LWS_TOKZE_ENDED)
|
|
|
|
goto bad_format;
|
|
|
|
|
2024-01-08 14:53:30 +01:00
|
|
|
if (wsi->a.vhost->listen_port != port &&
|
|
|
|
wsi->a.vhost->listen_port != CONTEXT_PORT_NO_LISTEN_SERVER) {
|
2018-11-13 09:33:13 +08:00
|
|
|
lwsl_info("%s: host port %d mismatches vhost port %d\n",
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
__func__, port, wsi->a.vhost->listen_port);
|
2018-11-13 09:33:13 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lwsl_debug("%s: host header OK\n", __func__);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bad_format:
|
|
|
|
lwsl_info("%s: bad host header format\n", __func__);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2018-11-29 08:47:49 +08:00
|
|
|
int
|
|
|
|
lws_http_to_fallback(struct lws *wsi, unsigned char *obuf, size_t olen)
|
|
|
|
{
|
|
|
|
const struct lws_role_ops *role = &role_ops_raw_skt;
|
|
|
|
const struct lws_protocols *p1, *protocol =
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
&wsi->a.vhost->protocols[wsi->a.vhost->raw_protocol_index];
|
2018-12-13 20:05:12 +08:00
|
|
|
char ipbuf[64];
|
2018-11-29 08:29:48 +08:00
|
|
|
int n;
|
2018-11-29 08:47:49 +08:00
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.vhost->listen_accept_role &&
|
|
|
|
lws_role_by_name(wsi->a.vhost->listen_accept_role))
|
|
|
|
role = lws_role_by_name(wsi->a.vhost->listen_accept_role);
|
2018-11-29 08:47:49 +08:00
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.vhost->listen_accept_protocol) {
|
|
|
|
p1 = lws_vhost_name_to_protocol(wsi->a.vhost,
|
|
|
|
wsi->a.vhost->listen_accept_protocol);
|
2018-11-29 08:47:49 +08:00
|
|
|
if (p1)
|
|
|
|
protocol = p1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lws_bind_protocol(wsi, protocol, __func__);
|
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
lws_role_transition(wsi, LWSIFR_SERVER, LRS_ESTABLISHED, role);
|
2018-11-29 08:47:49 +08:00
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
lws_header_table_detach(wsi, 0);
|
2018-11-29 08:47:49 +08:00
|
|
|
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
|
2020-03-06 10:16:12 +00:00
|
|
|
if (wsi->role_ops->adoption_cb[1])
|
|
|
|
n = wsi->role_ops->adoption_cb[1];
|
2018-11-29 08:29:48 +08:00
|
|
|
|
2018-12-13 20:05:12 +08:00
|
|
|
ipbuf[0] = '\0';
|
|
|
|
#if !defined(LWS_PLAT_OPTEE)
|
|
|
|
lws_get_peer_simple(wsi, ipbuf, sizeof(ipbuf));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
lwsl_notice("%s: vh %s, peer: %s, role %s, "
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
"protocol %s, cb %d, ah %p\n", __func__, wsi->a.vhost->name,
|
2020-08-18 09:38:00 +01:00
|
|
|
ipbuf, role ? role->name : "null", protocol->name, n,
|
|
|
|
wsi->http.ah);
|
2018-11-29 08:29:48 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
if ((wsi->a.protocol->callback)(wsi, (enum lws_callback_reasons)n, wsi->user_space, NULL, 0))
|
2018-11-29 08:29:48 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
n = LWS_CALLBACK_RAW_RX;
|
|
|
|
if (wsi->role_ops->rx_cb[lwsi_role_server(wsi)])
|
|
|
|
n = wsi->role_ops->rx_cb[lwsi_role_server(wsi)];
|
2020-12-12 06:21:40 +00:00
|
|
|
if (wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)n, wsi->user_space, obuf, olen))
|
2018-11-29 08:47:49 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
ah http1.1 deal with pipelined headers properly
Connections must hold an ah for the whole time they are
processing one header set, even if eg, the headers are
fragmented and it involves network roundtrip times.
However on http1.1 / keepalive, it must drop the ah when
there are no more header sets to deal with, and reacquire
the ah later when more data appears. It's because the
time between header sets / http1.1 requests is unbounded
and the ah would be tied up forever.
But in the case that we got pipelined http1.1 requests,
even partial already buffered, we must keep the ah,
resetting it instead of dropping it. Because we store
the rx data conveniently in a per-tsi buffer since it only
does one thing at a time per thread, we cannot go back to
the event loop to await a new ah inside one service action.
But no problem since we definitely already have an ah,
let's just reuse it at http completion time if more rx is
already buffered.
NB: attack.sh makes request with echo | nc, this
accidentally sends a trailing '\n' from the echo showing
this problem. With this patch attack.sh can complete well.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-01-30 11:43:10 +08:00
|
|
|
int
|
|
|
|
lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
2015-12-17 18:25:25 +08:00
|
|
|
struct lws_context *context = lws_get_context(wsi);
|
2020-01-10 11:03:00 +00:00
|
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
2019-05-17 01:24:52 +01:00
|
|
|
#if defined(LWS_WITH_HTTP2)
|
2019-05-12 08:01:50 +01:00
|
|
|
struct allocated_headers *ah;
|
2019-05-17 01:24:52 +01:00
|
|
|
#endif
|
2017-03-07 16:06:05 +08:00
|
|
|
unsigned char *obuf = *buf;
|
2018-03-11 11:26:06 +08:00
|
|
|
#if defined(LWS_WITH_HTTP2)
|
|
|
|
char tbuf[128], *p;
|
|
|
|
#endif
|
2017-03-07 16:06:05 +08:00
|
|
|
size_t olen = len;
|
2018-03-11 11:26:06 +08:00
|
|
|
int n = 0, m, i;
|
2014-04-03 09:03:37 +08:00
|
|
|
|
2016-05-13 10:27:48 +08:00
|
|
|
if (len >= 10000000) {
|
|
|
|
lwsl_err("%s: assert: len %ld\n", __func__, (long)len);
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (!wsi->http.ah) {
|
2016-05-13 10:27:48 +08:00
|
|
|
lwsl_err("%s: assert: NULL ah\n", __func__);
|
|
|
|
assert(0);
|
|
|
|
}
|
2014-04-03 09:03:37 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
while (len) {
|
2018-04-11 13:39:42 +08:00
|
|
|
if (!lwsi_role_server(wsi) || !lwsi_role_http(wsi)) {
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsl_err("%s: bad wsi role 0x%x\n", __func__,
|
2019-10-31 11:01:39 +00:00
|
|
|
(int)lwsi_role(wsi));
|
2016-04-13 11:42:53 +08:00
|
|
|
goto bail_nuke_ah;
|
|
|
|
}
|
2016-01-21 10:54:14 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
i = (int)len;
|
|
|
|
m = lws_parse(wsi, *buf, &i);
|
2018-04-11 13:39:42 +08:00
|
|
|
lwsl_info("%s: parsed count %d\n", __func__, (int)len - i);
|
2018-03-07 18:15:17 +08:00
|
|
|
(*buf) += (int)len - i;
|
2020-12-12 06:21:40 +00:00
|
|
|
len = (unsigned int)i;
|
2017-03-07 16:06:05 +08:00
|
|
|
|
2018-11-29 08:47:49 +08:00
|
|
|
if (m == LPR_DO_FALLBACK) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* http parser went off the rails and
|
|
|
|
* LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_
|
|
|
|
* ACCEPT_CONFIG is set on this vhost.
|
|
|
|
*
|
|
|
|
* We are transitioning from http with an AH, to
|
|
|
|
* a backup role (raw-skt, by default). Drop
|
|
|
|
* the ah, bind to the role with mode as
|
|
|
|
* ESTABLISHED.
|
|
|
|
*/
|
|
|
|
raw_transition:
|
2017-03-07 16:06:05 +08:00
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
if (lws_http_to_fallback(wsi, obuf, olen)) {
|
|
|
|
lwsl_info("%s: fallback -> close\n", __func__);
|
2018-11-29 08:47:49 +08:00
|
|
|
goto bail_nuke_ah;
|
2018-11-29 08:29:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
(*buf) = obuf + olen;
|
2017-03-07 16:06:05 +08:00
|
|
|
|
2018-11-29 08:47:49 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (m) {
|
2015-12-04 09:23:56 +08:00
|
|
|
lwsl_info("lws_parse failed\n");
|
2014-04-03 09:03:37 +08:00
|
|
|
goto bail_nuke_ah;
|
|
|
|
}
|
|
|
|
|
2020-08-18 09:40:23 +01:00
|
|
|
/* coverity... */
|
|
|
|
if (!wsi->http.ah)
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE)
|
2014-04-03 09:03:37 +08:00
|
|
|
continue;
|
|
|
|
|
2016-02-28 10:55:31 +08:00
|
|
|
lwsl_parser("%s: lws_parse sees parsing complete\n", __func__);
|
2014-04-03 09:03:37 +08:00
|
|
|
|
2017-09-06 09:30:32 +08:00
|
|
|
/* select vhost */
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.vhost->listen_port &&
|
2018-09-04 08:06:46 +08:00
|
|
|
lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
|
2017-09-06 09:30:32 +08:00
|
|
|
struct lws_vhost *vhost = lws_select_vhost(
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
context, wsi->a.vhost->listen_port,
|
2017-09-06 09:30:32 +08:00
|
|
|
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
|
|
|
|
|
|
|
|
if (vhost)
|
vhost_destroy: use vhost wsi reference counting to trigger destroy
This changes the vhost destroy flow to only hand off the listen
socket if another vhost sharing it, and mark the vhost as
being_destroyed.
Each tsi calls lws_check_deferred_free() once a second, if it sees
any vhost being_destroyed there, it closes all wsi on its tsi on
the same vhost, one time.
As the wsi on the vhost complete close (ie, after libuv async close
if on libuv event loop), they decrement a reference count for all
wsi open on the vhost. The tsi who closes the last one then
completes the destroy flow for the vhost itself... it's random
which tsi completes the vhost destroy but since there are no
wsi left on the vhost, and it holds the context lock, nothing
can conflict.
The advantage of this is that owning tsi do the close for wsi
that are bound to the vhost under destruction, at a time when
they are guaranteed to be idle for service, and they do it with
both vhost and context locks owned, so no other service thread
can conflict for stuff protected by those either.
For the situation the user code may have allocations attached to
the vhost, this adds args to lws_vhost_destroy() to allow destroying
the user allocations just before the vhost is freed.
2018-06-16 09:31:07 +08:00
|
|
|
lws_vhost_bind_wsi(vhost, wsi);
|
2017-09-06 09:30:32 +08:00
|
|
|
} else
|
|
|
|
lwsl_info("no host\n");
|
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
if ((!lwsi_role_h2(wsi) || !lwsi_role_server(wsi)) &&
|
|
|
|
(!wsi->conn_stat_done))
|
|
|
|
wsi->conn_stat_done = 1;
|
2017-09-06 09:30:32 +08:00
|
|
|
|
2016-10-13 06:32:57 +08:00
|
|
|
/* check for unwelcome guests */
|
2020-02-28 10:31:04 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.context->reject_service_keywords) {
|
2016-10-13 06:32:57 +08:00
|
|
|
const struct lws_protocol_vhost_options *rej =
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.context->reject_service_keywords;
|
2016-10-13 06:32:57 +08:00
|
|
|
char ua[384], *msg = NULL;
|
|
|
|
|
|
|
|
if (lws_hdr_copy(wsi, ua, sizeof(ua) - 1,
|
2017-09-06 09:30:32 +08:00
|
|
|
WSI_TOKEN_HTTP_USER_AGENT) > 0) {
|
|
|
|
#ifdef LWS_WITH_ACCESS_LOG
|
2017-11-06 10:05:04 +08:00
|
|
|
char *uri_ptr = NULL;
|
|
|
|
int meth, uri_len;
|
2017-09-06 09:30:32 +08:00
|
|
|
#endif
|
2017-11-06 10:05:04 +08:00
|
|
|
ua[sizeof(ua) - 1] = '\0';
|
|
|
|
while (rej) {
|
|
|
|
if (!strstr(ua, rej->name)) {
|
|
|
|
rej = rej->next;
|
|
|
|
continue;
|
|
|
|
}
|
2017-09-06 09:30:32 +08:00
|
|
|
|
2017-11-06 10:05:04 +08:00
|
|
|
msg = strchr(rej->value, ' ');
|
|
|
|
if (msg)
|
|
|
|
msg++;
|
|
|
|
lws_return_http_status(wsi,
|
2020-12-12 06:21:40 +00:00
|
|
|
(unsigned int)atoi(rej->value), msg);
|
2017-09-06 09:30:32 +08:00
|
|
|
#ifdef LWS_WITH_ACCESS_LOG
|
2017-11-06 10:05:04 +08:00
|
|
|
meth = lws_http_get_uri_and_method(wsi,
|
|
|
|
&uri_ptr, &uri_len);
|
|
|
|
if (meth >= 0)
|
|
|
|
lws_prepare_access_log_info(wsi,
|
2018-08-14 08:00:25 +08:00
|
|
|
uri_ptr, uri_len, meth);
|
2016-10-13 06:32:57 +08:00
|
|
|
|
2017-11-06 10:05:04 +08:00
|
|
|
/* wsi close will do the log */
|
2019-08-18 06:29:34 +01:00
|
|
|
#endif
|
2017-11-06 10:05:04 +08:00
|
|
|
/*
|
|
|
|
* We don't want anything from
|
|
|
|
* this rejected guy. Follow
|
|
|
|
* the close flow, not the
|
|
|
|
* transaction complete flow.
|
|
|
|
*/
|
|
|
|
goto bail_nuke_ah;
|
2016-10-13 06:32:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
2020-01-10 11:03:00 +00:00
|
|
|
/*
|
|
|
|
* So he may have come to us requesting one or another kind
|
|
|
|
* of upgrade from http... but we may want to redirect him at
|
|
|
|
* http level. In that case, we need to check the redirect
|
|
|
|
* situation even though he's not actually wanting http and
|
|
|
|
* prioritize returning that if there is one.
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
const struct lws_http_mount *hit = NULL;
|
|
|
|
int uri_len = 0, ha, n;
|
|
|
|
char *uri_ptr = NULL;
|
|
|
|
|
|
|
|
n = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
|
|
|
|
if (n >= 0) {
|
|
|
|
hit = lws_find_mount(wsi, uri_ptr, uri_len);
|
|
|
|
if (hit) {
|
|
|
|
n = lws_http_redirect_hit(pt, wsi, hit, uri_ptr,
|
|
|
|
uri_len, &ha);
|
|
|
|
if (ha)
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-15 14:01:29 +08:00
|
|
|
|
2017-02-12 20:32:49 +08:00
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) {
|
|
|
|
lwsl_info("Changing to RAW mode\n");
|
2017-03-07 16:06:05 +08:00
|
|
|
goto raw_transition;
|
2017-02-12 20:32:49 +08:00
|
|
|
}
|
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_PRE_WS_SERVING_ACCEPT);
|
2015-12-04 08:43:54 +08:00
|
|
|
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
2014-04-03 09:03:37 +08:00
|
|
|
|
2016-01-21 10:54:14 +08:00
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
|
2018-10-31 13:38:37 +08:00
|
|
|
|
|
|
|
const char *up = lws_hdr_simple_ptr(wsi,
|
|
|
|
WSI_TOKEN_UPGRADE);
|
|
|
|
|
|
|
|
if (strcasecmp(up, "websocket") &&
|
|
|
|
strcasecmp(up, "h2c")) {
|
|
|
|
lwsl_info("Unknown upgrade '%s'\n", up);
|
|
|
|
|
|
|
|
if (lws_return_http_status(wsi,
|
|
|
|
HTTP_STATUS_FORBIDDEN, NULL) ||
|
|
|
|
lws_http_transaction_completed(wsi))
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
}
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
n = user_callback_handle_rxflow(wsi->a.protocol->callback,
|
2018-10-31 13:38:37 +08:00
|
|
|
wsi, LWS_CALLBACK_HTTP_CONFIRM_UPGRADE,
|
|
|
|
wsi->user_space, (char *)up, 0);
|
|
|
|
|
|
|
|
/* just hang up? */
|
|
|
|
|
|
|
|
if (n < 0)
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
|
|
|
|
/* callback returned headers already, do t_c? */
|
|
|
|
|
|
|
|
if (n > 0) {
|
|
|
|
if (lws_http_transaction_completed(wsi))
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
|
|
|
|
/* continue on */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* callback said 0, it was allowed */
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.vhost->options &
|
2018-11-13 09:33:13 +08:00
|
|
|
LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK &&
|
|
|
|
lws_confirm_host_header(wsi))
|
|
|
|
goto bail_nuke_ah;
|
|
|
|
|
2018-10-31 13:38:37 +08:00
|
|
|
if (!strcasecmp(up, "websocket")) {
|
2018-04-25 08:42:18 +08:00
|
|
|
#if defined(LWS_ROLE_WS)
|
2021-01-06 15:08:22 +00:00
|
|
|
lws_metrics_tag_wsi_add(wsi, "upg", "ws");
|
2016-01-21 10:54:14 +08:00
|
|
|
lwsl_info("Upgrade to ws\n");
|
|
|
|
goto upgrade_ws;
|
2018-04-25 08:42:18 +08:00
|
|
|
#endif
|
2016-01-21 10:54:14 +08:00
|
|
|
}
|
2017-11-14 07:35:05 +08:00
|
|
|
#if defined(LWS_WITH_HTTP2)
|
2018-10-31 13:38:37 +08:00
|
|
|
if (!strcasecmp(up, "h2c")) {
|
2021-01-06 15:08:22 +00:00
|
|
|
lws_metrics_tag_wsi_add(wsi, "upg", "h2c");
|
2016-04-10 09:33:54 +08:00
|
|
|
lwsl_info("Upgrade to h2c\n");
|
2016-01-21 10:54:14 +08:00
|
|
|
goto upgrade_h2c;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2016-01-21 10:54:14 +08:00
|
|
|
/* no upgrade ack... he remained as HTTP */
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: No upgrade\n", __func__, lws_wsi_tag(wsi));
|
2014-04-03 09:03:37 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.fop_fd = NULL;
|
2019-08-18 10:35:43 +01:00
|
|
|
#endif
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
lws_http_compression_validate(wsi);
|
|
|
|
#endif
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: ah %p\n", __func__, lws_wsi_tag(wsi),
|
2018-04-27 15:20:56 +08:00
|
|
|
(void *)wsi->http.ah);
|
2014-04-03 09:03:37 +08:00
|
|
|
|
2016-01-21 10:54:14 +08:00
|
|
|
n = lws_http_action(wsi);
|
2014-04-03 09:03:37 +08:00
|
|
|
|
2016-01-21 10:54:14 +08:00
|
|
|
return n;
|
2014-09-30 09:43:14 +08:00
|
|
|
|
2017-11-14 07:35:05 +08:00
|
|
|
#if defined(LWS_WITH_HTTP2)
|
2014-10-08 12:00:53 +08:00
|
|
|
upgrade_h2c:
|
|
|
|
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) {
|
2016-05-09 13:31:43 +08:00
|
|
|
lwsl_info("missing http2_settings\n");
|
2014-09-30 09:43:14 +08:00
|
|
|
goto bail_nuke_ah;
|
|
|
|
}
|
|
|
|
|
2016-05-09 13:31:43 +08:00
|
|
|
lwsl_info("h2c upgrade...\n");
|
2014-09-30 09:43:14 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);
|
|
|
|
/* convert the peer's HTTP-Settings */
|
2018-03-11 11:26:06 +08:00
|
|
|
n = lws_b64_decode_string(p, tbuf, sizeof(tbuf));
|
2014-10-08 12:00:53 +08:00
|
|
|
if (n < 0) {
|
|
|
|
lwsl_parser("HTTP2_SETTINGS too long\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-05-12 08:01:50 +01:00
|
|
|
wsi->upgraded_to_http2 = 1;
|
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
/* adopt the header info */
|
|
|
|
|
2019-05-12 08:01:50 +01:00
|
|
|
ah = wsi->http.ah;
|
|
|
|
lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE,
|
|
|
|
&role_ops_h2);
|
|
|
|
|
|
|
|
/* http2 union member has http union struct at start */
|
|
|
|
wsi->http.ah = ah;
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!wsi->h2.h2n) {
|
2020-01-02 08:32:23 +00:00
|
|
|
wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n");
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!wsi->h2.h2n)
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lws_h2_init(wsi);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
/* HTTP2 union */
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
lws_h2_settings(wsi, &wsi->h2.h2n->peer_set, (uint8_t *)tbuf, n);
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2021-11-08 10:09:35 +00:00
|
|
|
if (lws_hpack_dynamic_size(wsi, (int)wsi->h2.h2n->peer_set.s[
|
|
|
|
H2SET_HEADER_TABLE_SIZE]))
|
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-03-11 11:26:06 +08:00
|
|
|
strcpy(tbuf, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
|
|
|
|
"Connection: Upgrade\x0d\x0a"
|
|
|
|
"Upgrade: h2c\x0d\x0a\x0d\x0a");
|
|
|
|
m = (int)strlen(tbuf);
|
2020-12-12 06:21:40 +00:00
|
|
|
n = lws_issue_raw(wsi, (unsigned char *)tbuf, (unsigned int)m);
|
2018-03-11 11:26:06 +08:00
|
|
|
if (n != m) {
|
2014-10-08 12:00:53 +08:00
|
|
|
lwsl_debug("http2 switch: ERROR writing to socket\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-09-30 09:43:14 +08:00
|
|
|
return 0;
|
2014-10-08 12:00:53 +08:00
|
|
|
#endif
|
2018-04-25 08:42:18 +08:00
|
|
|
#if defined(LWS_ROLE_WS)
|
2014-09-30 08:15:49 +08:00
|
|
|
upgrade_ws:
|
2018-03-11 11:26:06 +08:00
|
|
|
if (lws_process_ws_upgrade(wsi))
|
2014-04-03 09:03:37 +08:00
|
|
|
goto bail_nuke_ah;
|
2016-07-23 14:18:25 +08:00
|
|
|
|
2016-01-21 10:54:14 +08:00
|
|
|
return 0;
|
2018-04-25 08:42:18 +08:00
|
|
|
#endif
|
2014-04-03 09:03:37 +08:00
|
|
|
} /* while all chars are handled */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bail_nuke_ah:
|
|
|
|
/* drop the header info */
|
2016-02-27 11:42:22 +08:00
|
|
|
lws_header_table_detach(wsi, 1);
|
ah owns rxbuf
This is intended to solve a longstanding problem with the
relationship between http/1.1 keep-alive and the service
loop.
Ah now contain an rx buffer which is used during header
processing, and the ah may not be detached from the wsi
until the rx buffer is exhausted.
Having the rx buffer in the ah means we can delay using the
rx until a later service loop.
Ah which have pending rx force POLLIN service on the wsi
they are attached to automatically, so we can interleave
general service / connections with draining each ah rx
buffer.
The possible http/1.1 situations and their dispositions are:
1) exactly one set of http headers come. After processing,
the ah is detached since no pending rx left. If more
headers come later, a fresh ah is aqcuired when available
and the rx flow control blocks the read until then.
2) more that one whole set of headers come and we remain in
http mode (no upgrade). The ah is left attached and
returns to the service loop after the first set of headers.
We will get forced service due to the ah having pending
content (respecting flowcontrol) and process the pending
rx in the ah. If we use it all up, we will detach the
ah.
3) one set of http headers come with ws traffic appended.
We service the headers, do the upgrade, and keep the ah
until the remaining ws content is used. When we
exhausted the ws traffix in the ah rx buffer, we
detach the ah.
Since there can be any amount of http/1.1 pipelining on a
connection, and each may be expensive to service, it's now
enforced there is a return to the service loop after each
header set is serviced on a connection.
When I added the forced service for ah with pending buffering,
I added support for it to the windows plat code. However this
is untested.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-15 12:37:04 +08:00
|
|
|
|
2014-04-03 09:03:37 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
2014-04-03 09:03:37 +08:00
|
|
|
|
2019-11-18 09:19:08 +00:00
|
|
|
int LWS_WARN_UNUSED_RESULT
|
2016-01-21 10:57:39 +08:00
|
|
|
lws_http_transaction_completed(struct lws *wsi)
|
2014-10-17 08:38:44 +08:00
|
|
|
{
|
2019-11-18 09:19:08 +00:00
|
|
|
int n;
|
|
|
|
|
|
|
|
if (wsi->http.cgi_transaction_complete)
|
|
|
|
return 0;
|
2016-04-12 16:26:03 +08:00
|
|
|
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
if (lws_has_buffered_out(wsi)
|
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
|| wsi->http.comp_ctx.buflist_comp ||
|
|
|
|
wsi->http.comp_ctx.may_have_more
|
|
|
|
#endif
|
|
|
|
) {
|
2018-06-16 10:38:17 +08:00
|
|
|
/*
|
|
|
|
* ...so he tried to send something large as the http reply,
|
|
|
|
* it went as a partial, but he immediately said the
|
|
|
|
* transaction was completed.
|
|
|
|
*
|
|
|
|
* Defer the transaction completed until the last part of the
|
|
|
|
* partial is sent.
|
|
|
|
*/
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: deferring due to partial\n", __func__,
|
|
|
|
lws_wsi_tag(wsi));
|
2018-06-16 10:38:17 +08:00
|
|
|
wsi->http.deferred_transaction_completed = 1;
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
2018-06-16 10:38:17 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-07-05 06:07:03 +01:00
|
|
|
/*
|
|
|
|
* Are we finishing the transaction before we have consumed any body?
|
|
|
|
*
|
|
|
|
* For h1 this would kill keepalive pipelining, and for h2, considering
|
|
|
|
* it can extend over multiple DATA frames, it would kill the network
|
|
|
|
* connection.
|
|
|
|
*/
|
|
|
|
if (wsi->http.rx_content_length && wsi->http.rx_content_remain) {
|
|
|
|
/*
|
|
|
|
* are we already in LRS_DISCARD_BODY and didn't clear the
|
|
|
|
* remaining before trying to complete the transaction again?
|
|
|
|
*/
|
|
|
|
if (lwsi_state(wsi) == LRS_DISCARD_BODY)
|
|
|
|
return -1;
|
|
|
|
/*
|
|
|
|
* let's defer transaction completed processing until we
|
|
|
|
* discarded the remaining body
|
|
|
|
*/
|
|
|
|
lwsi_set_state(wsi, LRS_DISCARD_BODY);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-06-16 10:38:17 +08:00
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
#if defined(LWS_WITH_SYS_METRICS)
|
|
|
|
{
|
|
|
|
char tmp[10];
|
|
|
|
|
|
|
|
lws_snprintf(tmp, sizeof(tmp), "%u", wsi->http.response_code);
|
|
|
|
lws_metrics_tag_wsi_add(wsi, "status", tmp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s\n", __func__, lws_wsi_tag(wsi));
|
2018-04-17 15:35:15 +08:00
|
|
|
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
lws_http_compression_destroy(wsi);
|
|
|
|
#endif
|
2016-04-15 12:00:23 +08:00
|
|
|
lws_access_log(wsi);
|
|
|
|
|
2019-11-18 09:19:08 +00:00
|
|
|
if (!wsi->hdr_parsing_completed
|
|
|
|
#if defined(LWS_WITH_CGI)
|
|
|
|
&& !wsi->http.cgi
|
|
|
|
#endif
|
|
|
|
) {
|
2018-09-02 06:51:16 +08:00
|
|
|
char peer[64];
|
2019-01-11 13:13:19 +08:00
|
|
|
|
|
|
|
#if !defined(LWS_PLAT_OPTEE)
|
2018-09-02 06:51:16 +08:00
|
|
|
lws_get_peer_simple(wsi, peer, sizeof(peer) - 1);
|
2019-01-11 13:13:19 +08:00
|
|
|
#else
|
|
|
|
peer[0] = '\0';
|
|
|
|
#endif
|
2018-09-02 06:51:16 +08:00
|
|
|
peer[sizeof(peer) - 1] = '\0';
|
2020-08-03 15:52:50 +01:00
|
|
|
lwsl_info("%s: (from %s) ignoring, ah parsing incomplete\n",
|
2018-09-02 06:51:16 +08:00
|
|
|
__func__, peer);
|
2017-06-28 09:58:44 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-18 09:19:08 +00:00
|
|
|
#if defined(LWS_WITH_CGI)
|
|
|
|
if (wsi->http.cgi) {
|
|
|
|
lwsl_debug("%s: cleaning cgi\n", __func__);
|
|
|
|
wsi->http.cgi_transaction_complete = 1;
|
|
|
|
lws_cgi_remove_and_kill(wsi);
|
2020-02-12 10:12:39 +00:00
|
|
|
lws_spawn_piped_destroy(&wsi->http.cgi->lsp);
|
2020-07-17 15:35:28 +01:00
|
|
|
lws_sul_cancel(&wsi->http.cgi->sul_grace);
|
2019-11-18 09:19:08 +00:00
|
|
|
|
|
|
|
lws_free_set_NULL(wsi->http.cgi);
|
|
|
|
wsi->http.cgi_transaction_complete = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-10-17 08:38:44 +08:00
|
|
|
/* if we can't go back to accept new headers, drop the connection */
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->mux_substream)
|
2018-08-14 08:00:25 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (wsi->seen_zero_length_recv)
|
|
|
|
return 1;
|
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
if (wsi->http.conn_type != HTTP_CONNECTION_KEEP_ALIVE) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: close connection\n", __func__, lws_wsi_tag(wsi));
|
2014-10-17 08:38:44 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[0], __func__))
|
2016-06-18 09:00:04 +08:00
|
|
|
return 1;
|
2016-06-08 10:07:02 +08:00
|
|
|
|
2017-12-07 18:48:21 +08:00
|
|
|
/*
|
|
|
|
* otherwise set ourselves up ready to go again, but because we have no
|
|
|
|
* idea about the wsi writability, we make put it in a holding state
|
|
|
|
* until we can verify POLLOUT. The part of this that confirms POLLOUT
|
|
|
|
* with no partials is in lws_server_socket_service() below.
|
|
|
|
*/
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: setting DEF_ACT from 0x%x: %p\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), (int)wsi->wsistate, wsi->buflist);
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_DEFERRING_ACTION);
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.tx_content_length = 0;
|
|
|
|
wsi->http.tx_content_remain = 0;
|
ah http1.1 deal with pipelined headers properly
Connections must hold an ah for the whole time they are
processing one header set, even if eg, the headers are
fragmented and it involves network roundtrip times.
However on http1.1 / keepalive, it must drop the ah when
there are no more header sets to deal with, and reacquire
the ah later when more data appears. It's because the
time between header sets / http1.1 requests is unbounded
and the ah would be tied up forever.
But in the case that we got pipelined http1.1 requests,
even partial already buffered, we must keep the ah,
resetting it instead of dropping it. Because we store
the rx data conveniently in a per-tsi buffer since it only
does one thing at a time per thread, we cannot go back to
the event loop to await a new ah inside one service action.
But no problem since we definitely already have an ah,
let's just reuse it at http completion time if more rx is
already buffered.
NB: attack.sh makes request with echo | nc, this
accidentally sends a trailing '\n' from the echo showing
this problem. With this patch attack.sh can complete well.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-01-30 11:43:10 +08:00
|
|
|
wsi->hdr_parsing_completed = 0;
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
wsi->sending_chunked = 0;
|
2016-04-20 06:10:56 +08:00
|
|
|
#ifdef LWS_WITH_ACCESS_LOG
|
2018-04-27 19:16:50 +08:00
|
|
|
wsi->http.access_log.sent = 0;
|
2016-04-20 06:10:56 +08:00
|
|
|
#endif
|
2019-11-16 03:06:51 +00:00
|
|
|
#if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
|
|
|
|
if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
|
|
|
|
wsi->http.fop_fd != NULL)
|
|
|
|
lws_vfs_file_close(&wsi->http.fop_fd);
|
|
|
|
#endif
|
2016-04-12 16:26:03 +08:00
|
|
|
|
2019-11-18 09:19:08 +00:00
|
|
|
n = NO_PENDING_TIMEOUT;
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.vhost->keepalive_timeout)
|
2016-04-12 16:26:03 +08:00
|
|
|
n = PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE;
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_set_timeout(wsi, (enum pending_timeout)n, wsi->a.vhost->keepalive_timeout);
|
2015-10-21 08:16:34 +08:00
|
|
|
|
ah http1.1 deal with pipelined headers properly
Connections must hold an ah for the whole time they are
processing one header set, even if eg, the headers are
fragmented and it involves network roundtrip times.
However on http1.1 / keepalive, it must drop the ah when
there are no more header sets to deal with, and reacquire
the ah later when more data appears. It's because the
time between header sets / http1.1 requests is unbounded
and the ah would be tied up forever.
But in the case that we got pipelined http1.1 requests,
even partial already buffered, we must keep the ah,
resetting it instead of dropping it. Because we store
the rx data conveniently in a per-tsi buffer since it only
does one thing at a time per thread, we cannot go back to
the event loop to await a new ah inside one service action.
But no problem since we definitely already have an ah,
let's just reuse it at http completion time if more rx is
already buffered.
NB: attack.sh makes request with echo | nc, this
accidentally sends a trailing '\n' from the echo showing
this problem. With this patch attack.sh can complete well.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-01-30 11:43:10 +08:00
|
|
|
/*
|
|
|
|
* We already know we are on http1.1 / keepalive and the next thing
|
|
|
|
* coming will be another header set.
|
|
|
|
*
|
|
|
|
* If there is no pending rx and we still have the ah, drop it and
|
|
|
|
* reacquire a new ah when the new headers start to arrive. (Otherwise
|
|
|
|
* we needlessly hog an ah indefinitely.)
|
|
|
|
*
|
|
|
|
* However if there is pending rx and we know from the keepalive state
|
|
|
|
* that is already at least the start of another header set, simply
|
|
|
|
* reset the existing header table and keep it.
|
2016-01-29 09:06:22 +08:00
|
|
|
*/
|
2018-04-27 15:20:56 +08:00
|
|
|
if (wsi->http.ah) {
|
2019-09-12 05:41:19 +01:00
|
|
|
// lws_buflist_describe(&wsi->buflist, wsi, __func__);
|
2018-04-17 15:35:15 +08:00
|
|
|
if (!lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: nothing in buflist, detaching ah\n",
|
|
|
|
__func__, lws_wsi_tag(wsi));
|
2016-02-27 11:42:22 +08:00
|
|
|
lws_header_table_detach(wsi, 1);
|
2018-04-11 13:39:42 +08:00
|
|
|
#ifdef LWS_WITH_TLS
|
2017-03-16 10:46:31 +08:00
|
|
|
/*
|
|
|
|
* additionally... if we are hogging an SSL instance
|
|
|
|
* with no pending pipelined headers (or ah now), and
|
|
|
|
* SSL is scarce, drop this connection without waiting
|
|
|
|
*/
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.vhost->tls.use_ssl &&
|
|
|
|
wsi->a.context->simultaneous_ssl_restriction &&
|
|
|
|
wsi->a.context->simultaneous_ssl ==
|
|
|
|
wsi->a.context->simultaneous_ssl_restriction) {
|
2017-10-16 12:52:32 +08:00
|
|
|
lwsl_info("%s: simultaneous_ssl_restriction\n",
|
|
|
|
__func__);
|
2017-03-16 10:46:31 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
2017-08-15 07:58:53 +08:00
|
|
|
} else {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: resetting/keeping ah as pipeline\n",
|
|
|
|
__func__, lws_wsi_tag(wsi));
|
2018-01-14 10:18:32 +08:00
|
|
|
lws_header_table_reset(wsi, 0);
|
2017-08-15 07:58:53 +08:00
|
|
|
/*
|
|
|
|
* If we kept the ah, we should restrict the amount
|
|
|
|
* of time we are willing to keep it. Otherwise it
|
|
|
|
* will be bound the whole time the connection remains
|
|
|
|
* open.
|
|
|
|
*/
|
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->keepalive_timeout);
|
2017-08-15 07:58:53 +08:00
|
|
|
}
|
2017-12-01 11:09:32 +08:00
|
|
|
/* If we're (re)starting on headers, need other implied init */
|
2018-04-27 15:20:56 +08:00
|
|
|
if (wsi->http.ah)
|
|
|
|
wsi->http.ah->ues = URIES_IDLE;
|
2018-01-14 11:32:45 +08:00
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
//lwsi_set_state(wsi, LRS_ESTABLISHED); // !!!
|
2018-01-14 10:18:32 +08:00
|
|
|
} else
|
2018-04-17 15:35:15 +08:00
|
|
|
if (lws_buflist_next_segment_len(&wsi->buflist, NULL))
|
2018-01-14 10:18:32 +08:00
|
|
|
if (lws_header_table_attach(wsi, 0))
|
|
|
|
lwsl_debug("acquired ah\n");
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: keep-alive await new transaction (state 0x%x)\n",
|
|
|
|
__func__, lws_wsi_tag(wsi), (int)wsi->wsistate);
|
2017-12-07 18:48:21 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-17 08:38:44 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2020-01-02 08:32:23 +00:00
|
|
|
int
|
ah http1.1 deal with pipelined headers properly
Connections must hold an ah for the whole time they are
processing one header set, even if eg, the headers are
fragmented and it involves network roundtrip times.
However on http1.1 / keepalive, it must drop the ah when
there are no more header sets to deal with, and reacquire
the ah later when more data appears. It's because the
time between header sets / http1.1 requests is unbounded
and the ah would be tied up forever.
But in the case that we got pipelined http1.1 requests,
even partial already buffered, we must keep the ah,
resetting it instead of dropping it. Because we store
the rx data conveniently in a per-tsi buffer since it only
does one thing at a time per thread, we cannot go back to
the event loop to await a new ah inside one service action.
But no problem since we definitely already have an ah,
let's just reuse it at http completion time if more rx is
already buffered.
NB: attack.sh makes request with echo | nc, this
accidentally sends a trailing '\n' from the echo showing
this problem. With this patch attack.sh can complete well.
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-01-30 11:43:10 +08:00
|
|
|
lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
|
|
|
|
const char *other_headers, int other_headers_len)
|
2013-11-11 07:30:33 +08:00
|
|
|
{
|
2015-12-17 18:25:25 +08:00
|
|
|
struct lws_context *context = lws_get_context(wsi);
|
2016-01-19 03:34:24 +08:00
|
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
2018-11-23 08:47:56 +08:00
|
|
|
unsigned char *response = pt->serv_buf + LWS_PRE;
|
2016-12-12 13:36:25 +08:00
|
|
|
#if defined(LWS_WITH_RANGES)
|
2017-12-01 11:09:32 +08:00
|
|
|
struct lws_range_parsing *rp = &wsi->http.range;
|
2016-12-12 13:36:25 +08:00
|
|
|
#endif
|
2018-11-23 08:47:56 +08:00
|
|
|
int ret = 0, cclen = 8, n = HTTP_STATUS_OK;
|
2016-04-22 08:53:49 +08:00
|
|
|
char cache_control[50], *cc = "no-store";
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_fop_flags_t fflags = LWS_O_RDONLY;
|
|
|
|
const struct lws_plat_file_ops *fops;
|
|
|
|
lws_filepos_t total_content_length;
|
2014-10-08 12:00:53 +08:00
|
|
|
unsigned char *p = response;
|
2016-05-19 12:34:35 +08:00
|
|
|
unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
|
2018-11-23 08:47:56 +08:00
|
|
|
const char *vpath;
|
2016-12-12 13:36:25 +08:00
|
|
|
#if defined(LWS_WITH_RANGES)
|
|
|
|
int ranges;
|
|
|
|
#endif
|
2013-11-11 07:30:33 +08:00
|
|
|
|
2018-03-07 19:57:34 +08:00
|
|
|
if (wsi->handling_404)
|
|
|
|
n = HTTP_STATUS_NOT_FOUND;
|
|
|
|
|
2017-03-03 12:38:10 +08:00
|
|
|
/*
|
|
|
|
* We either call the platform fops .open with first arg platform fops,
|
|
|
|
* or we call fops_zip .open with first arg platform fops, and fops_zip
|
|
|
|
* open will decide whether to switch to fops_zip or stay with fops_def.
|
|
|
|
*
|
2017-12-01 11:09:32 +08:00
|
|
|
* If wsi->http.fop_fd is already set, the caller already opened it
|
2017-03-03 12:38:10 +08:00
|
|
|
*/
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!wsi->http.fop_fd) {
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
fops = lws_vfs_select_fops(wsi->a.context->fops, file, &vpath);
|
2017-03-03 12:38:10 +08:00
|
|
|
fflags |= lws_vfs_prepare_flags(wsi);
|
2022-02-17 06:37:42 +00:00
|
|
|
wsi->http.fop_fd = fops->LWS_FOP_OPEN(fops, wsi->a.context->fops,
|
2017-03-03 12:38:10 +08:00
|
|
|
file, vpath, &fflags);
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!wsi->http.fop_fd) {
|
2018-04-13 06:43:11 +08:00
|
|
|
lwsl_info("%s: Unable to open: '%s': errno %d\n",
|
|
|
|
__func__, file, errno);
|
2018-11-23 08:47:56 +08:00
|
|
|
if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND,
|
|
|
|
NULL))
|
2018-04-13 06:43:11 +08:00
|
|
|
return -1;
|
2019-12-23 11:31:57 +00:00
|
|
|
return !wsi->mux_substream;
|
2017-03-03 12:38:10 +08:00
|
|
|
}
|
2017-02-12 20:32:49 +08:00
|
|
|
}
|
2019-11-15 20:12:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Caution... wsi->http.fop_fd is live from here
|
|
|
|
*/
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.filelen = lws_vfs_get_length(wsi->http.fop_fd);
|
|
|
|
total_content_length = wsi->http.filelen;
|
2017-02-12 20:32:49 +08:00
|
|
|
|
2016-12-12 13:36:25 +08:00
|
|
|
#if defined(LWS_WITH_RANGES)
|
2017-12-01 11:09:32 +08:00
|
|
|
ranges = lws_ranges_init(wsi, rp, wsi->http.filelen);
|
2013-11-11 07:30:33 +08:00
|
|
|
|
2016-12-12 13:36:25 +08:00
|
|
|
lwsl_debug("Range count %d\n", ranges);
|
|
|
|
/*
|
|
|
|
* no ranges -> 200;
|
|
|
|
* 1 range -> 206 + Content-Type: normal; Content-Range;
|
|
|
|
* more -> 206 + Content-Type: multipart/byteranges
|
|
|
|
* Repeat the true Content-Type in each multipart header
|
|
|
|
* along with Content-Range
|
|
|
|
*/
|
|
|
|
if (ranges < 0) {
|
|
|
|
/* it means he expressed a range in Range:, but it was illegal */
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_return_http_status(wsi,
|
|
|
|
HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, NULL);
|
2016-12-12 13:36:25 +08:00
|
|
|
if (lws_http_transaction_completed(wsi))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail; /* <0 means just hang up */
|
2016-12-12 13:36:25 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
lws_vfs_file_close(&wsi->http.fop_fd);
|
2017-03-03 12:38:10 +08:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
return 0; /* == 0 means we did the transaction complete */
|
2016-12-12 13:36:25 +08:00
|
|
|
}
|
|
|
|
if (ranges)
|
|
|
|
n = HTTP_STATUS_PARTIAL_CONTENT;
|
|
|
|
#endif
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
if (lws_add_http_header_status(wsi, (unsigned int)n, &p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2016-12-12 13:36:25 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if ((wsi->http.fop_fd->flags & (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |
|
2017-03-03 12:38:10 +08:00
|
|
|
LWS_FOP_FLAG_COMPR_IS_GZIP)) ==
|
|
|
|
(LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP | LWS_FOP_FLAG_COMPR_IS_GZIP)) {
|
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_ENCODING,
|
|
|
|
(unsigned char *)"gzip", 4, &p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2017-03-03 12:38:10 +08:00
|
|
|
lwsl_info("file is being provided in gzip\n");
|
|
|
|
}
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* if we know its very compressible, and we can use
|
|
|
|
* compression, then use the most preferred compression
|
|
|
|
* method that the client said he will accept
|
|
|
|
*/
|
|
|
|
|
2019-04-05 21:13:59 +08:00
|
|
|
if (!wsi->interpreting && (
|
|
|
|
!strncmp(content_type, "text/", 5) ||
|
|
|
|
!strcmp(content_type, "application/javascript") ||
|
|
|
|
!strcmp(content_type, "image/svg+xml")))
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
lws_http_compression_apply(wsi, NULL, &p, end, 0);
|
|
|
|
}
|
|
|
|
#endif
|
2017-03-03 12:38:10 +08:00
|
|
|
|
2017-08-12 20:47:23 +08:00
|
|
|
if (
|
2016-12-12 13:36:25 +08:00
|
|
|
#if defined(LWS_WITH_RANGES)
|
2017-08-12 20:47:23 +08:00
|
|
|
ranges < 2 &&
|
|
|
|
#endif
|
|
|
|
content_type && content_type[0])
|
2017-11-06 10:05:04 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_TYPE,
|
2016-08-13 11:17:53 +02:00
|
|
|
(unsigned char *)content_type,
|
2017-11-06 10:05:04 +08:00
|
|
|
(int)strlen(content_type),
|
|
|
|
&p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2016-12-12 13:36:25 +08:00
|
|
|
|
2017-08-12 20:47:23 +08:00
|
|
|
#if defined(LWS_WITH_RANGES)
|
2016-12-12 13:36:25 +08:00
|
|
|
if (ranges >= 2) { /* multipart byteranges */
|
2018-03-12 09:28:26 +08:00
|
|
|
lws_strncpy(wsi->http.multipart_content_type, content_type,
|
|
|
|
sizeof(wsi->http.multipart_content_type));
|
|
|
|
|
2017-11-06 10:05:04 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_TYPE,
|
|
|
|
(unsigned char *)
|
|
|
|
"multipart/byteranges; "
|
|
|
|
"boundary=_lws",
|
|
|
|
20, &p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2016-12-12 13:36:25 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* our overall content length has to include
|
|
|
|
*
|
|
|
|
* - (n + 1) x "_lws\r\n"
|
|
|
|
* - n x Content-Type: xxx/xxx\r\n
|
|
|
|
* - n x Content-Range: bytes xxx-yyy/zzz\r\n
|
|
|
|
* - n x /r/n
|
|
|
|
* - the actual payloads (aggregated in rp->agg)
|
|
|
|
*
|
|
|
|
* Precompute it for the main response header
|
|
|
|
*/
|
|
|
|
|
2017-11-06 10:05:04 +08:00
|
|
|
total_content_length = (lws_filepos_t)rp->agg +
|
|
|
|
6 /* final _lws\r\n */;
|
2016-12-12 13:36:25 +08:00
|
|
|
|
|
|
|
lws_ranges_reset(rp);
|
|
|
|
while (lws_ranges_next(rp)) {
|
|
|
|
n = lws_snprintf(cache_control, sizeof(cache_control),
|
|
|
|
"bytes %llu-%llu/%llu",
|
|
|
|
rp->start, rp->end, rp->extent);
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
total_content_length = total_content_length +
|
|
|
|
(lws_filepos_t)(
|
2017-10-16 12:52:32 +08:00
|
|
|
6 /* header _lws\r\n */ +
|
|
|
|
/* Content-Type: xxx/xxx\r\n */
|
2020-12-12 06:21:40 +00:00
|
|
|
14 + (int)strlen(content_type) + 2 +
|
2017-10-16 12:52:32 +08:00
|
|
|
/* Content-Range: xxxx\r\n */
|
|
|
|
15 + n + 2 +
|
2020-12-12 06:21:40 +00:00
|
|
|
2); /* /r/n */
|
2016-12-12 13:36:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
lws_ranges_reset(rp);
|
|
|
|
lws_ranges_next(rp);
|
2016-08-13 11:17:53 +02:00
|
|
|
}
|
2016-05-19 15:28:31 +08:00
|
|
|
|
2016-12-12 13:36:25 +08:00
|
|
|
if (ranges == 1) {
|
2017-11-06 10:05:04 +08:00
|
|
|
total_content_length = (lws_filepos_t)rp->agg;
|
2017-10-16 12:52:32 +08:00
|
|
|
n = lws_snprintf(cache_control, sizeof(cache_control),
|
|
|
|
"bytes %llu-%llu/%llu",
|
|
|
|
rp->start, rp->end, rp->extent);
|
2016-12-12 13:36:25 +08:00
|
|
|
|
2017-11-06 10:05:04 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_RANGE,
|
2016-12-12 13:36:25 +08:00
|
|
|
(unsigned char *)cache_control,
|
|
|
|
n, &p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2016-12-12 13:36:25 +08:00
|
|
|
}
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.range.inside = 0;
|
2016-12-12 13:36:25 +08:00
|
|
|
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ACCEPT_RANGES,
|
|
|
|
(unsigned char *)"bytes", 5, &p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2016-12-12 13:36:25 +08:00
|
|
|
#endif
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream) {
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
/* for http/1.1 ... */
|
|
|
|
if (!wsi->sending_chunked
|
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
&& !wsi->http.lcs
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
/* ... if not already using chunked and not using an
|
|
|
|
* http compression translation, then send the naive
|
|
|
|
* content length
|
|
|
|
*/
|
2018-01-14 20:09:41 +08:00
|
|
|
if (lws_add_http_header_content_length(wsi,
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
total_content_length, &p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2018-01-14 20:09:41 +08:00
|
|
|
} else {
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
if (wsi->http.lcs) {
|
2018-09-04 08:06:46 +08:00
|
|
|
|
|
|
|
/* ...otherwise, for http 1 it must go chunked.
|
|
|
|
* For the compression case, the reason is we
|
|
|
|
* compress on the fly and do not know the
|
|
|
|
* compressed content-length until it has all
|
|
|
|
* been sent. Http/1.1 pipelining must be able
|
|
|
|
* to know where the transaction boundaries are
|
|
|
|
* ... so chunking...
|
|
|
|
*/
|
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_TRANSFER_ENCODING,
|
|
|
|
(unsigned char *)"chunked", 7,
|
|
|
|
&p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2018-09-04 08:06:46 +08:00
|
|
|
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
/*
|
|
|
|
* ...this is fun, isn't it :-) For h1 that is
|
|
|
|
* using an http compression translation, the
|
|
|
|
* compressor must chunk its output privately.
|
|
|
|
*
|
|
|
|
* h2 doesn't need (or support) any of this
|
|
|
|
* crap.
|
|
|
|
*/
|
|
|
|
lwsl_debug("setting chunking\n");
|
|
|
|
wsi->http.comp_ctx.chunking = 1;
|
|
|
|
}
|
|
|
|
#endif
|
2018-01-14 20:09:41 +08:00
|
|
|
}
|
2016-05-19 15:28:31 +08:00
|
|
|
}
|
2014-10-12 14:31:47 +08:00
|
|
|
|
2021-12-07 14:20:47 +00:00
|
|
|
if (wsi->cache_no) {
|
|
|
|
cc = cache_control;
|
|
|
|
cclen = sprintf(cache_control, "no-cache");
|
|
|
|
}
|
|
|
|
else if (wsi->cache_secs && wsi->cache_reuse) {
|
2018-08-13 16:49:58 +08:00
|
|
|
if (!wsi->cache_revalidate) {
|
2016-04-22 08:53:49 +08:00
|
|
|
cc = cache_control;
|
2018-08-13 16:49:58 +08:00
|
|
|
cclen = sprintf(cache_control, "%s, max-age=%u",
|
2021-12-07 14:20:47 +00:00
|
|
|
intermediates[wsi->cache_intermediaries],
|
|
|
|
wsi->cache_secs);
|
2016-04-22 08:53:49 +08:00
|
|
|
} else {
|
2018-08-13 16:49:58 +08:00
|
|
|
cc = cache_control;
|
2018-09-04 08:06:46 +08:00
|
|
|
cclen = sprintf(cache_control,
|
2021-12-07 14:20:47 +00:00
|
|
|
"must-revalidate, %s, max-age=%u",
|
|
|
|
intermediates[wsi->cache_intermediaries],
|
|
|
|
wsi->cache_secs);
|
2016-04-22 08:53:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-15 05:05:39 +08:00
|
|
|
/* Only add cache control if its not specified by any other_headers. */
|
|
|
|
if (!other_headers ||
|
2018-11-15 16:33:54 +08:00
|
|
|
(!strstr(other_headers, "cache-control") &&
|
|
|
|
!strstr(other_headers, "Cache-Control"))) {
|
2018-11-23 08:47:56 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_CACHE_CONTROL,
|
2018-10-15 05:05:39 +08:00
|
|
|
(unsigned char *)cc, cclen, &p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2018-10-15 05:05:39 +08:00
|
|
|
}
|
2016-04-22 08:53:49 +08:00
|
|
|
|
2013-11-11 07:30:33 +08:00
|
|
|
if (other_headers) {
|
2014-10-12 14:31:47 +08:00
|
|
|
if ((end - p) < other_headers_len)
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2020-12-12 06:21:40 +00:00
|
|
|
memcpy(p, other_headers, (unsigned int)other_headers_len);
|
2014-10-12 14:31:47 +08:00
|
|
|
p += other_headers_len;
|
2013-11-11 07:30:33 +08:00
|
|
|
}
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
ret = lws_write(wsi, response, lws_ptr_diff_size_t(p, response), LWS_WRITE_HTTP_HEADERS);
|
2014-10-08 12:00:53 +08:00
|
|
|
if (ret != (p - response)) {
|
2017-10-16 12:52:32 +08:00
|
|
|
lwsl_err("_write returned %d from %ld\n", ret,
|
|
|
|
(long)(p - response));
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2013-11-11 07:30:33 +08:00
|
|
|
}
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.filepos = 0;
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_ISSUING_FILE);
|
2013-11-11 07:30:33 +08:00
|
|
|
|
2019-08-01 12:56:29 +01:00
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_HEAD_URI)) {
|
|
|
|
/* we do not emit the body */
|
2019-11-15 20:12:58 +00:00
|
|
|
lws_vfs_file_close(&wsi->http.fop_fd);
|
2019-08-01 12:56:29 +01:00
|
|
|
if (lws_http_transaction_completed(wsi))
|
2019-11-15 20:12:58 +00:00
|
|
|
goto bail;
|
2019-08-01 12:56:29 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
|
|
|
|
return 0;
|
2019-11-15 20:12:58 +00:00
|
|
|
|
|
|
|
bail:
|
|
|
|
lws_vfs_file_close(&wsi->http.fop_fd);
|
|
|
|
|
|
|
|
return -1;
|
2013-11-11 07:30:33 +08:00
|
|
|
}
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
2013-11-11 07:30:33 +08:00
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
int lws_serve_http_file_fragment(struct lws *wsi)
|
2018-04-20 10:33:23 +08:00
|
|
|
{
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
struct lws_context *context = wsi->a.context;
|
2018-04-20 10:33:23 +08:00
|
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
|
|
|
struct lws_process_html_args args;
|
|
|
|
lws_filepos_t amount, poss;
|
|
|
|
unsigned char *p, *pstart;
|
|
|
|
#if defined(LWS_WITH_RANGES)
|
|
|
|
unsigned char finished = 0;
|
2021-07-20 10:13:26 +01:00
|
|
|
#endif
|
|
|
|
#if defined(LWS_ROLE_H2)
|
|
|
|
struct lws *nwsi;
|
2018-04-20 10:33:23 +08:00
|
|
|
#endif
|
|
|
|
int n, m;
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
lwsl_debug("wsi->mux_substream %d\n", wsi->mux_substream);
|
2018-04-20 10:33:23 +08:00
|
|
|
|
|
|
|
do {
|
|
|
|
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
/* priority 1: buffered output */
|
|
|
|
|
2018-08-20 12:02:26 +08:00
|
|
|
if (lws_has_buffered_out(wsi)) {
|
|
|
|
if (lws_issue_raw(wsi, NULL, 0) < 0) {
|
2018-04-20 10:33:23 +08:00
|
|
|
lwsl_info("%s: closing\n", __func__);
|
|
|
|
goto file_had_it;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
/* priority 2: buffered pre-compression-transform */
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
if (wsi->http.comp_ctx.buflist_comp ||
|
|
|
|
wsi->http.comp_ctx.may_have_more) {
|
|
|
|
enum lws_write_protocol wp = LWS_WRITE_HTTP;
|
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("%s: completing comp partial (buflist %p, may %d)\n",
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
__func__, wsi->http.comp_ctx.buflist_comp,
|
|
|
|
wsi->http.comp_ctx.may_have_more);
|
|
|
|
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) &&
|
|
|
|
lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol).
|
|
|
|
write_role_protocol(wsi, NULL, 0, &wp) < 0) {
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
lwsl_info("%s signalling to close\n", __func__);
|
|
|
|
goto file_had_it;
|
|
|
|
}
|
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-04-20 10:33:23 +08:00
|
|
|
if (wsi->http.filepos == wsi->http.filelen)
|
|
|
|
goto all_sent;
|
|
|
|
|
|
|
|
n = 0;
|
2020-01-02 08:32:23 +00:00
|
|
|
p = pstart = pt->serv_buf + LWS_H2_FRAME_HEADER_LENGTH;
|
2018-04-20 10:33:23 +08:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_RANGES)
|
|
|
|
if (wsi->http.range.count_ranges && !wsi->http.range.inside) {
|
|
|
|
|
|
|
|
lwsl_notice("%s: doing range start %llu\n", __func__,
|
|
|
|
wsi->http.range.start);
|
|
|
|
|
|
|
|
if ((long long)lws_vfs_file_seek_cur(wsi->http.fop_fd,
|
2020-12-12 06:21:40 +00:00
|
|
|
(lws_fileofs_t)wsi->http.range.start -
|
|
|
|
(lws_fileofs_t)wsi->http.filepos) < 0)
|
2018-04-20 10:33:23 +08:00
|
|
|
goto file_had_it;
|
|
|
|
|
|
|
|
wsi->http.filepos = wsi->http.range.start;
|
|
|
|
|
|
|
|
if (wsi->http.range.count_ranges > 1) {
|
|
|
|
n = lws_snprintf((char *)p,
|
|
|
|
context->pt_serv_buf_size -
|
|
|
|
LWS_H2_FRAME_HEADER_LENGTH,
|
|
|
|
"_lws\x0d\x0a"
|
|
|
|
"Content-Type: %s\x0d\x0a"
|
2018-11-23 08:47:56 +08:00
|
|
|
"Content-Range: bytes "
|
|
|
|
"%llu-%llu/%llu\x0d\x0a"
|
2018-04-20 10:33:23 +08:00
|
|
|
"\x0d\x0a",
|
|
|
|
wsi->http.multipart_content_type,
|
|
|
|
wsi->http.range.start,
|
|
|
|
wsi->http.range.end,
|
|
|
|
wsi->http.range.extent);
|
|
|
|
p += n;
|
|
|
|
}
|
|
|
|
|
|
|
|
wsi->http.range.budget = wsi->http.range.end -
|
|
|
|
wsi->http.range.start + 1;
|
|
|
|
wsi->http.range.inside = 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-07-20 10:13:26 +01:00
|
|
|
poss = context->pt_serv_buf_size;
|
|
|
|
|
|
|
|
#if defined(LWS_ROLE_H2)
|
|
|
|
/*
|
|
|
|
* If it's h2, restrict any lump that we are sending to the
|
|
|
|
* max h2 frame size the peer indicated he could handle in
|
|
|
|
* his SETTINGS
|
|
|
|
*/
|
|
|
|
nwsi = lws_get_network_wsi(wsi);
|
|
|
|
if (nwsi->h2.h2n &&
|
|
|
|
poss > (lws_filepos_t)nwsi->h2.h2n->peer_set.s[H2SET_MAX_FRAME_SIZE])
|
|
|
|
poss = (lws_filepos_t)nwsi->h2.h2n->peer_set.s[H2SET_MAX_FRAME_SIZE];
|
|
|
|
#endif
|
|
|
|
poss = poss - (lws_filepos_t)(n + LWS_H2_FRAME_HEADER_LENGTH);
|
2018-04-20 10:33:23 +08:00
|
|
|
|
|
|
|
if (wsi->http.tx_content_length)
|
|
|
|
if (poss > wsi->http.tx_content_remain)
|
|
|
|
poss = wsi->http.tx_content_remain;
|
|
|
|
|
|
|
|
/*
|
2020-01-02 08:32:23 +00:00
|
|
|
* If there is a hint about how much we will do well to send at
|
2018-04-20 10:33:23 +08:00
|
|
|
* one time, restrict ourselves to only trying to send that.
|
|
|
|
*/
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.protocol->tx_packet_size &&
|
|
|
|
poss > wsi->a.protocol->tx_packet_size)
|
|
|
|
poss = wsi->a.protocol->tx_packet_size;
|
2018-04-20 10:33:23 +08:00
|
|
|
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit)) {
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_filepos_t txc = (unsigned int)lws_rops_func_fidx(wsi->role_ops,
|
roles: compress role ops structs
role ops are usually only sparsely filled, there are currently 20
function pointers but several roles only fill in two. No single
role has more than 14 of the ops. On a 32/64 bit build this part
of the ops struct takes a fixed 80 / 160 bytes then.
First reduce the type of the callback reason part from uint16_t to
uint8_t, this saves 12 bytes unconditionally.
Change to a separate function pointer array with a nybble index
array, it costs 10 bytes for the index and a pointer to the
separate array, for 32-bit the cost is
2 + (4 x ops_used)
and for 64-bit
6 + (8 x ops_used)
for 2 x ops_used it means 32-bit: 10 vs 80 / 64-bit: 22 vs 160
For a typical system with h1 (9), h2 (14), listen (2), netlink (2),
pipe (1), raw_skt (3), ws (12), == 43 ops_used out of 140, it means
the .rodata for this reduced from 32-bit: 560 -> 174 (386 byte
saving) and 64-bit: 1120 -> 350 (770 byte saving)
This doesn't account for the changed function ops calling code, two
ways were tried, a preprocessor macro and explicit functions
For an x86_64 gcc 10 build with most options, release mode,
.text + .rodata
before patch: 553282
accessor macro: 552714 (568 byte saving)
accessor functions: 553674 (392 bytes worse than without patch)
therefore we went with the macros
2020-10-19 13:55:21 +01:00
|
|
|
LWS_ROPS_tx_credit).
|
|
|
|
tx_credit(wsi, LWSTXCR_US_TO_PEER, 0);
|
2018-04-20 10:33:23 +08:00
|
|
|
|
|
|
|
if (!txc) {
|
2020-01-02 08:32:23 +00:00
|
|
|
/*
|
|
|
|
* We shouldn't've been able to get the
|
|
|
|
* WRITEABLE if we are skint
|
|
|
|
*/
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_notice("%s: %s: no tx credit\n", __func__,
|
|
|
|
lws_wsi_tag(wsi));
|
2020-01-02 08:32:23 +00:00
|
|
|
|
2018-04-20 10:33:23 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (txc < poss)
|
|
|
|
poss = txc;
|
|
|
|
|
|
|
|
/*
|
2020-01-02 08:32:23 +00:00
|
|
|
* Tracking consumption of the actual payload amount
|
|
|
|
* will be handled when the role data frame is sent...
|
2018-04-20 10:33:23 +08:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_RANGES)
|
|
|
|
if (wsi->http.range.count_ranges) {
|
|
|
|
if (wsi->http.range.count_ranges > 1)
|
|
|
|
poss -= 7; /* allow for final boundary */
|
|
|
|
if (poss > wsi->http.range.budget)
|
|
|
|
poss = wsi->http.range.budget;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (wsi->sending_chunked) {
|
|
|
|
/* we need to drop the chunk size in here */
|
|
|
|
p += 10;
|
|
|
|
/* allow for the chunk to grow by 128 in translation */
|
|
|
|
poss -= 10 + 128;
|
|
|
|
}
|
|
|
|
|
2020-07-08 18:27:47 +01:00
|
|
|
amount = 0;
|
2018-04-20 10:33:23 +08:00
|
|
|
if (lws_vfs_file_read(wsi->http.fop_fd, &amount, p, poss) < 0)
|
|
|
|
goto file_had_it; /* caller will close */
|
|
|
|
|
|
|
|
if (wsi->sending_chunked)
|
|
|
|
n = (int)amount;
|
|
|
|
else
|
|
|
|
n = lws_ptr_diff(p, pstart) + (int)amount;
|
|
|
|
|
|
|
|
lwsl_debug("%s: sending %d\n", __func__, n);
|
|
|
|
|
|
|
|
if (n) {
|
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)context->timeout_secs);
|
2018-04-20 10:33:23 +08:00
|
|
|
|
|
|
|
if (wsi->interpreting) {
|
|
|
|
args.p = (char *)p;
|
|
|
|
args.len = n;
|
2020-12-12 06:21:40 +00:00
|
|
|
args.max_len = (int)(unsigned int)poss + 128;
|
|
|
|
args.final = wsi->http.filepos + (unsigned int)n ==
|
|
|
|
wsi->http.filelen;
|
2018-04-20 10:33:23 +08:00
|
|
|
args.chunked = wsi->sending_chunked;
|
|
|
|
if (user_callback_handle_rxflow(
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->protocols[
|
2018-04-20 10:33:23 +08:00
|
|
|
(int)wsi->protocol_interpret_idx].callback,
|
|
|
|
wsi, LWS_CALLBACK_PROCESS_HTML,
|
|
|
|
wsi->user_space, &args, 0) < 0)
|
|
|
|
goto file_had_it;
|
|
|
|
n = args.len;
|
|
|
|
p = (unsigned char *)args.p;
|
|
|
|
} else
|
|
|
|
p = pstart;
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_RANGES)
|
|
|
|
if (wsi->http.range.send_ctr + 1 ==
|
|
|
|
wsi->http.range.count_ranges && // last range
|
|
|
|
wsi->http.range.count_ranges > 1 && // was 2+ ranges (ie, multipart)
|
|
|
|
wsi->http.range.budget - amount == 0) {// final part
|
|
|
|
n += lws_snprintf((char *)pstart + n, 6,
|
|
|
|
"_lws\x0d\x0a"); // append trailing boundary
|
|
|
|
lwsl_debug("added trailing boundary\n");
|
|
|
|
}
|
|
|
|
#endif
|
2020-12-12 06:21:40 +00:00
|
|
|
m = lws_write(wsi, p, (unsigned int)n, wsi->http.filepos + amount ==
|
2018-11-23 08:47:56 +08:00
|
|
|
wsi->http.filelen ?
|
|
|
|
LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP);
|
2018-04-20 10:33:23 +08:00
|
|
|
if (m < 0)
|
|
|
|
goto file_had_it;
|
|
|
|
|
|
|
|
wsi->http.filepos += amount;
|
|
|
|
|
|
|
|
#if defined(LWS_WITH_RANGES)
|
|
|
|
if (wsi->http.range.count_ranges >= 1) {
|
|
|
|
wsi->http.range.budget -= amount;
|
|
|
|
if (wsi->http.range.budget == 0) {
|
|
|
|
lwsl_notice("range budget exhausted\n");
|
|
|
|
wsi->http.range.inside = 0;
|
|
|
|
wsi->http.range.send_ctr++;
|
|
|
|
|
|
|
|
if (lws_ranges_next(&wsi->http.range) < 1) {
|
|
|
|
finished = 1;
|
|
|
|
goto all_sent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (m != n) {
|
|
|
|
/* adjust for what was not sent */
|
|
|
|
if (lws_vfs_file_seek_cur(wsi->http.fop_fd,
|
|
|
|
m - n) ==
|
|
|
|
(lws_fileofs_t)-1)
|
|
|
|
goto file_had_it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
all_sent:
|
http: compression methods
Add generic http compression layer eanbled at cmake with LWS_WITH_HTTP_STREAM_COMPRESSION.
This is wholly a feature of the HTTP role (used by h1 and h2 roles) and doesn't exist
outside that context.
Currently provides 'deflate' and 'br' compression methods for server side only.
'br' requires also -DLWS_WITH_HTTP_BROTLI=1 at cmake and the brotli libraries (available in
your distro already) and dev package.
Other compression methods can be added nicely using an ops struct.
The built-in file serving stuff will use this is the client says he can handle it, and the
mimetype of the file either starts with "text/" (html and css etc) or is the mimetype of
Javascript.
zlib allocates quite a bit while in use, it seems to be around 256KiB per stream. So this
is only useful on relatively strong servers with lots of memory. However for some usecases
where you are serving a lot of css and js assets, it's a nice help.
The patch performs special treatment for http/1.1 pipelining, since the compression is
performed on the fly the compressed content-length is not known until the end. So for h1
only, chunked transfer-encoding is automatically added so pipelining can continue of the
connection.
For h2 the chunking is neither supported nor required, so it "just works".
User code can also request to add a compression transform before the reply headers were
sent using the new api
LWS_VISIBLE int
lws_http_compression_apply(struct lws *wsi, const char *name,
unsigned char **p, unsigned char *end, char decomp);
... this allows transparent compression of dynamically generated HTTP. The requested
compression (eg, "deflate") is only applied if the client headers indicated it was
supported, otherwise it's a NOP.
Name may be NULL in which case the first compression method in the internal table at
stream.c that is mentioned as acceptable by the client will be used.
NOTE: the compression translation, same as h2 support, relies on the user code using
LWS_WRITE_HTTP and then LWS_WRITE_HTTP_FINAL on the last part written. The internal
lws fileserving code already does this.
2018-09-02 14:43:05 +08:00
|
|
|
if ((!lws_has_buffered_out(wsi)
|
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
&& !wsi->http.comp_ctx.buflist_comp &&
|
|
|
|
!wsi->http.comp_ctx.may_have_more
|
|
|
|
#endif
|
|
|
|
) && (wsi->http.filepos >= wsi->http.filelen
|
2018-04-20 10:33:23 +08:00
|
|
|
#if defined(LWS_WITH_RANGES)
|
|
|
|
|| finished)
|
|
|
|
#else
|
|
|
|
)
|
|
|
|
#endif
|
2018-12-13 20:05:12 +08:00
|
|
|
) {
|
2018-04-20 10:33:23 +08:00
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
|
|
|
/* we might be in keepalive, so close it off here */
|
|
|
|
lws_vfs_file_close(&wsi->http.fop_fd);
|
|
|
|
|
|
|
|
lwsl_debug("file completed\n");
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.protocol->callback &&
|
|
|
|
user_callback_handle_rxflow(wsi->a.protocol->callback,
|
2018-11-23 08:47:56 +08:00
|
|
|
wsi, LWS_CALLBACK_HTTP_FILE_COMPLETION,
|
|
|
|
wsi->user_space, NULL, 0) < 0) {
|
2018-04-20 10:33:23 +08:00
|
|
|
/*
|
|
|
|
* For http/1.x, the choices from
|
|
|
|
* transaction_completed are either
|
|
|
|
* 0 to use the connection for pipelined
|
|
|
|
* or nonzero to hang it up.
|
|
|
|
*
|
|
|
|
* However for http/2. while we are
|
|
|
|
* still interested in hanging up the
|
|
|
|
* nwsi if there was a network-level
|
|
|
|
* fatal error, simply completing the
|
|
|
|
* transaction is a matter of the stream
|
|
|
|
* state, not the root connection at the
|
|
|
|
* network level
|
|
|
|
*/
|
2023-12-18 11:13:07 +00:00
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->mux_substream)
|
2018-04-20 10:33:23 +08:00
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-12-18 11:13:07 +00:00
|
|
|
if (wsi->http.ah)
|
|
|
|
lws_header_table_reset(wsi, 0);
|
|
|
|
|
|
|
|
|
2018-04-20 10:33:23 +08:00
|
|
|
return 1; /* >0 indicates completed */
|
|
|
|
}
|
2018-12-13 20:05:12 +08:00
|
|
|
/*
|
|
|
|
* while(1) here causes us to spam the whole file contents into
|
|
|
|
* a hugely bloated output buffer if it ever can't send the
|
|
|
|
* whole chunk...
|
|
|
|
*/
|
|
|
|
} while (!lws_send_pipe_choked(wsi));
|
2018-04-20 10:33:23 +08:00
|
|
|
|
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
|
|
|
|
return 0; /* indicates further processing must be done */
|
|
|
|
|
|
|
|
file_had_it:
|
|
|
|
lws_vfs_file_close(&wsi->http.fop_fd);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#endif
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2020-01-02 08:32:23 +00:00
|
|
|
void
|
2015-12-04 11:08:32 +08:00
|
|
|
lws_server_get_canonical_hostname(struct lws_context *context,
|
2018-04-27 08:27:16 +08:00
|
|
|
const struct lws_context_creation_info *info)
|
2014-04-12 10:07:02 +08:00
|
|
|
{
|
2017-10-16 12:52:32 +08:00
|
|
|
if (lws_check_opt(info->options,
|
|
|
|
LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))
|
2014-04-12 10:07:02 +08:00
|
|
|
return;
|
2019-08-18 10:35:43 +01:00
|
|
|
#if !defined(LWS_PLAT_FREERTOS)
|
2014-04-12 10:07:02 +08:00
|
|
|
/* find canonical hostname */
|
2020-08-19 07:19:48 +01:00
|
|
|
if (gethostname((char *)context->canonical_hostname,
|
|
|
|
sizeof(context->canonical_hostname) - 1))
|
|
|
|
lws_strncpy((char *)context->canonical_hostname, "unknown",
|
|
|
|
sizeof(context->canonical_hostname));
|
2014-04-12 10:07:02 +08:00
|
|
|
|
2021-06-18 07:28:23 +01:00
|
|
|
lwsl_cx_info(context, " canonical_hostname = %s\n",
|
|
|
|
context->canonical_hostname);
|
2015-11-02 20:34:12 +08:00
|
|
|
#else
|
|
|
|
(void)context;
|
|
|
|
#endif
|
2014-04-27 13:28:22 +02:00
|
|
|
}
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
2016-06-08 10:07:02 +08:00
|
|
|
|
2019-08-18 06:29:34 +01:00
|
|
|
int
|
2016-06-12 09:56:39 +08:00
|
|
|
lws_chunked_html_process(struct lws_process_html_args *args,
|
|
|
|
struct lws_process_html_state *s)
|
|
|
|
{
|
|
|
|
char *sp, buffer[32];
|
|
|
|
const char *pc;
|
|
|
|
int old_len, n;
|
|
|
|
|
|
|
|
/* do replacements */
|
|
|
|
sp = args->p;
|
|
|
|
old_len = args->len;
|
|
|
|
args->len = 0;
|
|
|
|
s->start = sp;
|
|
|
|
while (sp < args->p + old_len) {
|
|
|
|
|
|
|
|
if (args->len + 7 >= args->max_len) {
|
|
|
|
lwsl_err("Used up interpret padding\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((!s->pos && *sp == '$') || s->pos) {
|
2016-06-27 05:53:38 +08:00
|
|
|
int hits = 0, hit = 0;
|
2016-06-12 09:56:39 +08:00
|
|
|
|
|
|
|
if (!s->pos)
|
|
|
|
s->start = sp;
|
|
|
|
s->swallow[s->pos++] = *sp;
|
2016-08-28 09:28:55 +08:00
|
|
|
if (s->pos == sizeof(s->swallow) - 1)
|
2016-06-12 09:56:39 +08:00
|
|
|
goto skip;
|
|
|
|
for (n = 0; n < s->count_vars; n++)
|
2020-12-12 06:21:40 +00:00
|
|
|
if (!strncmp(s->swallow, s->vars[n], (unsigned int)s->pos)) {
|
2016-06-12 09:56:39 +08:00
|
|
|
hits++;
|
|
|
|
hit = n;
|
|
|
|
}
|
|
|
|
if (!hits) {
|
|
|
|
skip:
|
|
|
|
s->swallow[s->pos] = '\0';
|
2020-12-12 06:21:40 +00:00
|
|
|
memcpy(s->start, s->swallow, (unsigned int)s->pos);
|
2016-06-12 09:56:39 +08:00
|
|
|
args->len++;
|
|
|
|
s->pos = 0;
|
|
|
|
sp = s->start + 1;
|
|
|
|
continue;
|
|
|
|
}
|
2017-10-20 17:45:02 +08:00
|
|
|
if (hits == 1 && s->pos == (int)strlen(s->vars[hit])) {
|
2016-06-12 09:56:39 +08:00
|
|
|
pc = s->replace(s->data, hit);
|
|
|
|
if (!pc)
|
|
|
|
pc = "NULL";
|
2017-10-25 08:00:23 +08:00
|
|
|
n = (int)strlen(pc);
|
2016-06-12 09:56:39 +08:00
|
|
|
s->swallow[s->pos] = '\0';
|
|
|
|
if (n != s->pos) {
|
2018-11-23 08:47:56 +08:00
|
|
|
memmove(s->start + n, s->start + s->pos,
|
2020-12-12 06:21:40 +00:00
|
|
|
(unsigned int)(old_len - (sp - args->p) - 1));
|
2016-06-12 09:56:39 +08:00
|
|
|
old_len += (n - s->pos) + 1;
|
|
|
|
}
|
2020-12-12 06:21:40 +00:00
|
|
|
memcpy(s->start, pc, (unsigned int)n);
|
2016-06-12 09:56:39 +08:00
|
|
|
args->len++;
|
|
|
|
sp = s->start + 1;
|
|
|
|
|
|
|
|
s->pos = 0;
|
|
|
|
}
|
|
|
|
sp++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
args->len++;
|
|
|
|
sp++;
|
|
|
|
}
|
|
|
|
|
2018-01-14 20:09:41 +08:00
|
|
|
if (args->chunked) {
|
|
|
|
/* no space left for final chunk trailer */
|
|
|
|
if (args->final && args->len + 7 >= args->max_len)
|
|
|
|
return -1;
|
2016-06-12 09:56:39 +08:00
|
|
|
|
2018-01-14 20:09:41 +08:00
|
|
|
n = sprintf(buffer, "%X\x0d\x0a", args->len);
|
|
|
|
|
|
|
|
args->p -= n;
|
2020-12-12 06:21:40 +00:00
|
|
|
memcpy(args->p, buffer, (unsigned int)n);
|
2018-01-14 20:09:41 +08:00
|
|
|
args->len += n;
|
|
|
|
|
|
|
|
if (args->final) {
|
|
|
|
sp = args->p + args->len;
|
|
|
|
*sp++ = '\x0d';
|
|
|
|
*sp++ = '\x0a';
|
|
|
|
*sp++ = '0';
|
|
|
|
*sp++ = '\x0d';
|
|
|
|
*sp++ = '\x0a';
|
|
|
|
*sp++ = '\x0d';
|
|
|
|
*sp++ = '\x0a';
|
|
|
|
args->len += 7;
|
|
|
|
} else {
|
|
|
|
sp = args->p + args->len;
|
|
|
|
*sp++ = '\x0d';
|
|
|
|
*sp++ = '\x0a';
|
|
|
|
args->len += 2;
|
|
|
|
}
|
2016-06-12 09:56:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|