2010-11-08 20:20:42 +00:00
|
|
|
/*
|
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
2010-11-13 10:03:47 +00:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
2010-11-08 20:20:42 +00: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:
|
2010-11-08 20:20:42 +00: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.
|
2010-11-08 20:20:42 +00: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.
|
2010-11-08 20:20:42 +00:00
|
|
|
*/
|
|
|
|
|
2019-08-15 10:49:52 +01:00
|
|
|
#include "private-lib-core.h"
|
2010-11-08 20:20:42 +00:00
|
|
|
|
2020-02-28 15:50:15 +00:00
|
|
|
static const unsigned char lextable_h1[] = {
|
2019-08-15 10:49:52 +01:00
|
|
|
#include "lextable.h"
|
2013-01-18 01:55:48 +08:00
|
|
|
};
|
|
|
|
|
2014-03-09 11:49:21 +08:00
|
|
|
#define FAIL_CHAR 0x08
|
|
|
|
|
2019-02-26 17:18:24 +08:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
|
|
|
|
|
|
|
#define UHO_NLEN 0
|
|
|
|
#define UHO_VLEN 2
|
|
|
|
#define UHO_LL 4
|
|
|
|
#define UHO_NAME 8
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2017-10-06 16:07:57 +08:00
|
|
|
static struct allocated_headers *
|
|
|
|
_lws_create_ah(struct lws_context_per_thread *pt, ah_data_idx_t data_size)
|
|
|
|
{
|
|
|
|
struct allocated_headers *ah = lws_zalloc(sizeof(*ah), "ah struct");
|
|
|
|
|
|
|
|
if (!ah)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ah->data = lws_malloc(data_size, "ah data");
|
|
|
|
if (!ah->data) {
|
|
|
|
lws_free(ah);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-04-27 15:20:56 +08:00
|
|
|
ah->next = pt->http.ah_list;
|
|
|
|
pt->http.ah_list = ah;
|
2017-10-06 16:07:57 +08:00
|
|
|
ah->data_length = data_size;
|
2018-04-27 15:20:56 +08:00
|
|
|
pt->http.ah_pool_length++;
|
2017-10-06 16:07:57 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_info("%s: created ah %p (size %d): pool length %u\n", __func__,
|
|
|
|
ah, (int)data_size, (unsigned int)pt->http.ah_pool_length);
|
2017-10-06 16:07:57 +08:00
|
|
|
|
|
|
|
return ah;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
_lws_destroy_ah(struct lws_context_per_thread *pt, struct allocated_headers *ah)
|
|
|
|
{
|
2018-04-27 15:20:56 +08:00
|
|
|
lws_start_foreach_llp(struct allocated_headers **, a, pt->http.ah_list) {
|
2017-10-06 16:07:57 +08:00
|
|
|
if ((*a) == ah) {
|
|
|
|
*a = ah->next;
|
2018-04-27 15:20:56 +08:00
|
|
|
pt->http.ah_pool_length--;
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_info("%s: freed ah %p : pool length %u\n",
|
2019-06-07 11:11:46 +01:00
|
|
|
__func__, ah,
|
2020-01-02 08:32:23 +00:00
|
|
|
(unsigned int)pt->http.ah_pool_length);
|
2017-10-06 16:07:57 +08:00
|
|
|
if (ah->data)
|
|
|
|
lws_free(ah->data);
|
|
|
|
lws_free(ah);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} lws_end_foreach_llp(a, next);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-02-09 15:25:01 +08:00
|
|
|
void
|
|
|
|
_lws_header_table_reset(struct allocated_headers *ah)
|
|
|
|
{
|
|
|
|
/* init the ah to reflect no headers or data have appeared yet */
|
|
|
|
memset(ah->frag_index, 0, sizeof(ah->frag_index));
|
2017-10-13 10:33:02 +08:00
|
|
|
memset(ah->frags, 0, sizeof(ah->frags));
|
2017-02-09 15:25:01 +08:00
|
|
|
ah->nfrag = 0;
|
|
|
|
ah->pos = 0;
|
|
|
|
ah->http_response = 0;
|
2018-05-04 12:05:56 +08:00
|
|
|
ah->parser_state = WSI_TOKEN_NAME_PART;
|
|
|
|
ah->lextable_pos = 0;
|
2019-02-26 17:18:24 +08:00
|
|
|
ah->unk_pos = 0;
|
2020-06-26 07:34:27 +01:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
2019-02-26 17:18:24 +08:00
|
|
|
ah->unk_ll_head = 0;
|
|
|
|
ah->unk_ll_tail = 0;
|
|
|
|
#endif
|
2017-02-09 15:25:01 +08:00
|
|
|
}
|
|
|
|
|
2016-09-29 10:31:06 +08:00
|
|
|
// doesn't scrub the ah rxbuffer by default, parent must do if needed
|
|
|
|
|
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
|
|
|
void
|
2018-03-02 14:22:49 +08:00
|
|
|
__lws_header_table_reset(struct lws *wsi, int autoservice)
|
2016-01-26 20:56:56 +08:00
|
|
|
{
|
2018-04-27 15:20:56 +08:00
|
|
|
struct allocated_headers *ah = wsi->http.ah;
|
2016-02-27 11:42:22 +08:00
|
|
|
struct lws_context_per_thread *pt;
|
|
|
|
struct lws_pollfd *pfd;
|
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 we have the idea we're resetting 'our' ah, must be bound to one */
|
|
|
|
assert(ah);
|
|
|
|
/* ah also concurs with ownership */
|
|
|
|
assert(ah->wsi == wsi);
|
2016-02-09 09:15:02 +08:00
|
|
|
|
2017-02-09 15:25:01 +08:00
|
|
|
_lws_header_table_reset(ah);
|
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
|
|
|
|
|
|
|
/* since we will restart the ah, our new headers are not completed */
|
2017-06-28 09:55:34 +08:00
|
|
|
wsi->hdr_parsing_completed = 0;
|
2016-02-24 11:05:56 +08:00
|
|
|
|
2017-07-26 11:49:41 +08:00
|
|
|
/* while we hold the ah, keep a timeout on the wsi */
|
2018-03-02 14:22:49 +08:00
|
|
|
__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->timeout_secs_ah_idle);
|
2017-07-26 11:49:41 +08:00
|
|
|
|
2017-09-14 13:14:11 +08:00
|
|
|
time(&ah->assigned);
|
|
|
|
|
2018-05-06 07:19:21 +08:00
|
|
|
if (wsi->position_in_fds_table != LWS_NO_FDS_POS &&
|
|
|
|
lws_buflist_next_segment_len(&wsi->buflist, NULL) &&
|
2018-04-17 15:35:15 +08:00
|
|
|
autoservice) {
|
|
|
|
lwsl_debug("%s: service on readbuf ah\n", __func__);
|
|
|
|
|
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
|
|
|
pt = &wsi->a.context->pt[(int)wsi->tsi];
|
2018-04-17 15:35:15 +08:00
|
|
|
/*
|
|
|
|
* Unlike a normal connect, we have the headers already
|
|
|
|
* (or the first part of them anyway)
|
|
|
|
*/
|
|
|
|
pfd = &pt->fds[wsi->position_in_fds_table];
|
|
|
|
pfd->revents |= LWS_POLLIN;
|
|
|
|
lwsl_err("%s: calling service\n", __func__);
|
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_service_fd_tsi(wsi->a.context, pfd, wsi->tsi);
|
2016-02-24 11:05:56 +08:00
|
|
|
}
|
2016-01-26 20:56:56 +08:00
|
|
|
}
|
|
|
|
|
2018-03-02 14:22:49 +08:00
|
|
|
void
|
|
|
|
lws_header_table_reset(struct lws *wsi, int autoservice)
|
|
|
|
{
|
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];
|
2018-03-02 14:22:49 +08:00
|
|
|
|
|
|
|
lws_pt_lock(pt, __func__);
|
|
|
|
|
|
|
|
__lws_header_table_reset(wsi, autoservice);
|
|
|
|
|
|
|
|
lws_pt_unlock(pt);
|
|
|
|
}
|
|
|
|
|
2017-09-14 13:14:11 +08:00
|
|
|
static void
|
|
|
|
_lws_header_ensure_we_are_on_waiting_list(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];
|
2017-09-14 13:14:11 +08:00
|
|
|
struct lws_pollargs pa;
|
2018-04-27 15:20:56 +08:00
|
|
|
struct lws **pwsi = &pt->http.ah_wait_list;
|
2017-09-14 13:14:11 +08:00
|
|
|
|
|
|
|
while (*pwsi) {
|
|
|
|
if (*pwsi == wsi)
|
|
|
|
return;
|
2018-04-27 15:20:56 +08:00
|
|
|
pwsi = &(*pwsi)->http.ah_wait_list;
|
2017-09-14 13:14:11 +08:00
|
|
|
}
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: wsi: %s\n", __func__, lws_wsi_tag(wsi));
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah_wait_list = pt->http.ah_wait_list;
|
|
|
|
pt->http.ah_wait_list = wsi;
|
|
|
|
pt->http.ah_wait_list_length++;
|
2017-09-14 13:14:11 +08:00
|
|
|
|
|
|
|
/* we cannot accept input then */
|
|
|
|
|
|
|
|
_lws_change_pollfd(wsi, LWS_POLLIN, 0, &pa);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
__lws_remove_from_ah_waiting_list(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];
|
2018-04-27 15:20:56 +08:00
|
|
|
struct lws **pwsi =&pt->http.ah_wait_list;
|
2017-09-14 13:14:11 +08:00
|
|
|
|
|
|
|
while (*pwsi) {
|
|
|
|
if (*pwsi == wsi) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: wsi %s\n", __func__, lws_wsi_tag(wsi));
|
2017-09-14 13:14:11 +08:00
|
|
|
/* point prev guy to our next */
|
2018-04-27 15:20:56 +08:00
|
|
|
*pwsi = wsi->http.ah_wait_list;
|
2017-09-14 13:14:11 +08:00
|
|
|
/* we shouldn't point anywhere now */
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah_wait_list = NULL;
|
|
|
|
pt->http.ah_wait_list_length--;
|
2017-09-14 13:14:11 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2018-04-27 15:20:56 +08:00
|
|
|
pwsi = &(*pwsi)->http.ah_wait_list;
|
2017-09-14 13:14:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-21 10:57:39 +08:00
|
|
|
int LWS_WARN_UNUSED_RESULT
|
2016-02-27 11:42:22 +08:00
|
|
|
lws_header_table_attach(struct lws *wsi, int autoservice)
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +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;
|
2016-01-26 20:56:56 +08:00
|
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
|
|
|
struct lws_pollargs pa;
|
2015-12-25 12:44:12 +08:00
|
|
|
int n;
|
|
|
|
|
2020-02-25 13:28:25 +00:00
|
|
|
#if defined(LWS_ROLE_MQTT) && defined(LWS_WITH_CLIENT)
|
|
|
|
if (lwsi_role_mqtt(wsi))
|
|
|
|
goto connect_via_info2;
|
|
|
|
#endif
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: ah %p (tsi %d, count = %d) in\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), (void *)wsi->http.ah, wsi->tsi,
|
2018-04-27 15:20:56 +08:00
|
|
|
pt->http.ah_count_in_use);
|
2015-12-25 12:44:12 +08:00
|
|
|
|
2018-11-29 08:29:48 +08:00
|
|
|
if (!lwsi_role_http(wsi)) {
|
|
|
|
lwsl_err("%s: bad role %s\n", __func__, wsi->role_ops->name);
|
|
|
|
assert(0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
lws_pt_lock(pt, __func__);
|
|
|
|
|
2015-12-25 12:44:12 +08:00
|
|
|
/* if we are already bound to one, just clear it down */
|
2018-04-27 15:20:56 +08:00
|
|
|
if (wsi->http.ah) {
|
2017-09-14 13:14:11 +08:00
|
|
|
lwsl_info("%s: cleardown\n", __func__);
|
2015-12-25 12:44:12 +08:00
|
|
|
goto reset;
|
2016-01-26 20:56:56 +08:00
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = pt->http.ah_count_in_use == (int)context->max_http_header_pool;
|
2017-09-14 13:14:11 +08:00
|
|
|
#if defined(LWS_WITH_PEER_LIMITS)
|
2021-01-06 15:08:22 +00:00
|
|
|
if (!n)
|
2017-09-14 13:14:11 +08:00
|
|
|
n = lws_peer_confirm_ah_attach_ok(context, wsi->peer);
|
|
|
|
#endif
|
|
|
|
if (n) {
|
|
|
|
/*
|
|
|
|
* Pool is either all busy, or we don't want to give this
|
|
|
|
* particular guy an ah right now...
|
|
|
|
*
|
|
|
|
* Make sure we are on the waiting list, and return that we
|
|
|
|
* weren't able to provide the ah
|
|
|
|
*/
|
|
|
|
_lws_header_ensure_we_are_on_waiting_list(wsi);
|
2016-01-26 20:56:56 +08:00
|
|
|
|
|
|
|
goto bail;
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
}
|
2015-12-25 12:44:12 +08:00
|
|
|
|
2017-09-14 13:14:11 +08:00
|
|
|
__lws_remove_from_ah_waiting_list(wsi);
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah = _lws_create_ah(pt, context->max_http_header_data);
|
|
|
|
if (!wsi->http.ah) { /* we could not create an ah */
|
2017-10-06 16:07:57 +08:00
|
|
|
_lws_header_ensure_we_are_on_waiting_list(wsi);
|
2015-12-25 12:44:12 +08:00
|
|
|
|
2017-10-06 16:07:57 +08:00
|
|
|
goto bail;
|
|
|
|
}
|
2015-12-25 12:44:12 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->in_use = 1;
|
|
|
|
wsi->http.ah->wsi = wsi; /* mark our owner */
|
|
|
|
pt->http.ah_count_in_use++;
|
2016-01-26 20:56:56 +08:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
#if defined(LWS_WITH_PEER_LIMITS) && (defined(LWS_ROLE_H1) || \
|
|
|
|
defined(LWS_ROLE_H2))
|
2018-06-27 07:15:39 +08:00
|
|
|
lws_context_lock(context, "ah attach"); /* <========================= */
|
2017-09-14 13:14:11 +08:00
|
|
|
if (wsi->peer)
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->peer->http.count_ah++;
|
|
|
|
lws_context_unlock(context); /* ====================================> */
|
2017-09-14 13:14:11 +08:00
|
|
|
#endif
|
|
|
|
|
2016-01-26 20:56:56 +08:00
|
|
|
_lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa);
|
2015-12-25 12:44:12 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: did attach wsi %s: ah %p: count %d (on exit)\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), (void *)wsi->http.ah, pt->http.ah_count_in_use);
|
2015-12-25 12:44:12 +08:00
|
|
|
|
|
|
|
reset:
|
2018-03-02 14:22:49 +08:00
|
|
|
__lws_header_table_reset(wsi, autoservice);
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
lws_pt_unlock(pt);
|
|
|
|
|
2020-02-29 12:37:24 +00:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2020-02-25 13:28:25 +00:00
|
|
|
#if defined(LWS_ROLE_MQTT)
|
|
|
|
connect_via_info2:
|
|
|
|
#endif
|
2018-04-02 11:55:17 +08:00
|
|
|
if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED)
|
2018-05-10 16:13:26 +08:00
|
|
|
if (!lws_http_client_connect_via_info2(wsi))
|
2016-05-08 16:58:18 +08:00
|
|
|
/* our client connect has failed, the wsi
|
|
|
|
* has been closed
|
|
|
|
*/
|
|
|
|
return -1;
|
2016-02-29 14:19:16 +08:00
|
|
|
#endif
|
|
|
|
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
return 0;
|
2016-01-26 20:56:56 +08:00
|
|
|
|
|
|
|
bail:
|
|
|
|
lws_pt_unlock(pt);
|
|
|
|
|
|
|
|
return 1;
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
}
|
|
|
|
|
2018-03-05 16:49:28 +08:00
|
|
|
int __lws_header_table_detach(struct lws *wsi, int autoservice)
|
2014-11-07 11:20:59 +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-27 15:20:56 +08:00
|
|
|
struct allocated_headers *ah = wsi->http.ah;
|
2016-01-26 20:56:56 +08:00
|
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
|
|
|
struct lws_pollargs pa;
|
2017-09-14 13:14:11 +08:00
|
|
|
struct lws **pwsi, **pwsi_eligible;
|
2016-01-26 20:56:56 +08:00
|
|
|
time_t now;
|
|
|
|
|
2017-07-19 04:06:15 +08:00
|
|
|
__lws_remove_from_ah_waiting_list(wsi);
|
|
|
|
|
2017-06-28 12:13:13 +08:00
|
|
|
if (!ah)
|
|
|
|
return 0;
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: ah %p (tsi=%d, count = %d)\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), (void *)ah, wsi->tsi,
|
2018-04-27 15:20:56 +08:00
|
|
|
pt->http.ah_count_in_use);
|
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
|
|
|
|
2016-02-25 21:39:01 +08:00
|
|
|
/* we did have an ah attached */
|
2016-01-26 20:56:56 +08:00
|
|
|
time(&now);
|
2016-07-19 09:38:48 +08:00
|
|
|
if (ah->assigned && now - ah->assigned > 3) {
|
2016-02-19 11:47:52 +08:00
|
|
|
/*
|
|
|
|
* we're detaching the ah, but it was held an
|
|
|
|
* unreasonably long time
|
|
|
|
*/
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s: ah held %ds, role/state 0x%lx 0x%x,"
|
|
|
|
"\n", __func__, lws_wsi_tag(wsi),
|
|
|
|
(int)(now - ah->assigned),
|
2019-06-07 11:11:46 +01:00
|
|
|
(unsigned long)lwsi_role(wsi), lwsi_state(wsi));
|
2016-02-19 11:47:52 +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
|
|
|
|
2016-07-19 09:38:48 +08:00
|
|
|
ah->assigned = 0;
|
|
|
|
|
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 we think we're detaching one, there should be one in use */
|
2018-04-27 15:20:56 +08:00
|
|
|
assert(pt->http.ah_count_in_use > 0);
|
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
|
|
|
/* and this specific one should have been in use */
|
2016-07-19 09:38:48 +08:00
|
|
|
assert(ah->in_use);
|
2018-04-27 15:20:56 +08:00
|
|
|
memset(&wsi->http.ah, 0, sizeof(wsi->http.ah));
|
2018-04-27 12:49:42 +08:00
|
|
|
|
2017-09-14 13:14:11 +08:00
|
|
|
#if defined(LWS_WITH_PEER_LIMITS)
|
2018-04-27 12:49:42 +08:00
|
|
|
if (ah->wsi)
|
|
|
|
lws_peer_track_ah_detach(context, wsi->peer);
|
2017-09-14 13:14:11 +08:00
|
|
|
#endif
|
2018-04-27 12:49:42 +08:00
|
|
|
ah->wsi = NULL; /* no owner */
|
2020-02-29 12:37:24 +00:00
|
|
|
wsi->http.ah = NULL;
|
2015-12-25 12:44:12 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
pwsi = &pt->http.ah_wait_list;
|
2017-07-19 04:06:15 +08:00
|
|
|
|
2017-09-14 13:14:11 +08:00
|
|
|
/* oh there is nobody on the waiting list... leave the ah unattached */
|
|
|
|
if (!*pwsi)
|
|
|
|
goto nobody_usable_waiting;
|
2015-12-25 12:44:12 +08:00
|
|
|
|
2017-09-14 13:14:11 +08:00
|
|
|
/*
|
|
|
|
* at least one wsi on the same tsi is waiting, give it to oldest guy
|
|
|
|
* who is allowed to take it (if any)
|
|
|
|
*/
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: pt wait list %s\n", __func__, lws_wsi_tag(*pwsi));
|
2017-09-14 13:14:11 +08:00
|
|
|
wsi = NULL;
|
|
|
|
pwsi_eligible = NULL;
|
|
|
|
|
|
|
|
while (*pwsi) {
|
|
|
|
#if defined(LWS_WITH_PEER_LIMITS)
|
|
|
|
/* are we willing to give this guy an ah? */
|
|
|
|
if (!lws_peer_confirm_ah_attach_ok(context, (*pwsi)->peer))
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
wsi = *pwsi;
|
|
|
|
pwsi_eligible = pwsi;
|
|
|
|
}
|
2021-01-06 15:08:22 +00:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
pwsi = &(*pwsi)->http.ah_wait_list;
|
2017-09-14 13:14:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!wsi) /* everybody waiting already has too many ah... */
|
|
|
|
goto nobody_usable_waiting;
|
2015-12-25 12:44:12 +08:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("%s: transferring ah to last eligible wsi in wait list "
|
2020-12-25 05:54:19 +00:00
|
|
|
"%s (wsistate 0x%lx)\n", __func__, lws_wsi_tag(wsi),
|
2019-06-07 11:11:46 +01:00
|
|
|
(unsigned long)wsi->wsistate);
|
2016-01-26 20:56:56 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah = ah;
|
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
|
|
|
ah->wsi = wsi; /* new owner */
|
2017-09-14 13:14:11 +08:00
|
|
|
|
2018-03-02 14:22:49 +08:00
|
|
|
__lws_header_table_reset(wsi, autoservice);
|
2018-11-23 08:47:56 +08:00
|
|
|
#if defined(LWS_WITH_PEER_LIMITS) && (defined(LWS_ROLE_H1) || \
|
|
|
|
defined(LWS_ROLE_H2))
|
2018-06-27 07:15:39 +08:00
|
|
|
lws_context_lock(context, "ah detach"); /* <========================= */
|
2017-09-14 13:14:11 +08:00
|
|
|
if (wsi->peer)
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->peer->http.count_ah++;
|
2018-04-27 12:49:42 +08:00
|
|
|
lws_context_unlock(context); /* ====================================> */
|
2017-09-14 13:14:11 +08:00
|
|
|
#endif
|
2016-01-26 20:56:56 +08:00
|
|
|
|
2016-08-07 08:33:08 +08:00
|
|
|
/* clients acquire the ah and then insert themselves in fds table... */
|
2018-05-06 07:19:21 +08:00
|
|
|
if (wsi->position_in_fds_table != LWS_NO_FDS_POS) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: Enabling %s POLLIN\n", __func__, lws_wsi_tag(wsi));
|
2016-01-26 20:56:56 +08:00
|
|
|
|
2017-09-14 13:14:11 +08:00
|
|
|
/* he has been stuck waiting for an ah, but now his wait is
|
|
|
|
* over, let him progress */
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2016-08-07 08:33:08 +08:00
|
|
|
_lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa);
|
|
|
|
}
|
2016-01-26 20:56:56 +08:00
|
|
|
|
|
|
|
/* point prev guy to next guy in list instead */
|
2018-04-27 15:20:56 +08:00
|
|
|
*pwsi_eligible = wsi->http.ah_wait_list;
|
2016-02-25 21:39:01 +08:00
|
|
|
/* the guy who got one is out of the list */
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah_wait_list = NULL;
|
|
|
|
pt->http.ah_wait_list_length--;
|
2016-01-26 20:56:56 +08:00
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2018-04-02 11:55:17 +08:00
|
|
|
if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED) {
|
2017-06-12 13:36:24 +08:00
|
|
|
lws_pt_unlock(pt);
|
|
|
|
|
2018-05-10 16:13:26 +08:00
|
|
|
if (!lws_http_client_connect_via_info2(wsi)) {
|
2016-05-08 16:58:18 +08:00
|
|
|
/* our client connect has failed, the wsi
|
|
|
|
* has been closed
|
|
|
|
*/
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2017-06-12 13:36:24 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2016-02-29 14:19:16 +08:00
|
|
|
#endif
|
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
assert(!!pt->http.ah_wait_list_length ==
|
|
|
|
!!(lws_intptr_t)pt->http.ah_wait_list);
|
2016-01-26 20:56:56 +08:00
|
|
|
bail:
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: ah %p (tsi=%d, count = %d)\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), (void *)ah, pt->tid, pt->http.ah_count_in_use);
|
2017-09-14 13:14:11 +08:00
|
|
|
|
2014-12-04 23:59:35 +01:00
|
|
|
return 0;
|
2017-09-14 13:14:11 +08:00
|
|
|
|
|
|
|
nobody_usable_waiting:
|
|
|
|
lwsl_info("%s: nobody usable waiting\n", __func__);
|
2017-10-06 16:07:57 +08:00
|
|
|
_lws_destroy_ah(pt, ah);
|
2018-04-27 15:20:56 +08:00
|
|
|
pt->http.ah_count_in_use--;
|
2017-09-14 13:14:11 +08:00
|
|
|
|
|
|
|
goto bail;
|
2015-12-25 12:44:12 +08:00
|
|
|
}
|
2014-11-07 11:20:59 +08:00
|
|
|
|
2018-03-05 16:49:28 +08:00
|
|
|
int lws_header_table_detach(struct lws *wsi, int autoservice)
|
|
|
|
{
|
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-03-05 16:49:28 +08:00
|
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
|
|
|
int n;
|
|
|
|
|
|
|
|
lws_pt_lock(pt, __func__);
|
|
|
|
n = __lws_header_table_detach(wsi, autoservice);
|
|
|
|
lws_pt_unlock(pt);
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
int
|
2015-12-19 07:35:23 +08:00
|
|
|
lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (!wsi->http.ah)
|
2017-07-19 04:39:14 +08:00
|
|
|
return 0;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
n = wsi->http.ah->frag_index[h];
|
2015-12-19 07:35:23 +08:00
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
do {
|
|
|
|
if (!frag_idx)
|
2018-04-27 15:20:56 +08:00
|
|
|
return wsi->http.ah->frags[n].len;
|
|
|
|
n = wsi->http.ah->frags[n].nfrag;
|
2015-12-19 07:35:23 +08:00
|
|
|
} while (frag_idx-- && n);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
int len = 0;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (!wsi->http.ah)
|
2017-07-19 04:39:14 +08:00
|
|
|
return 0;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
n = wsi->http.ah->frag_index[h];
|
2014-04-02 19:45:42 +08:00
|
|
|
if (!n)
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
return 0;
|
|
|
|
do {
|
2018-04-27 15:20:56 +08:00
|
|
|
len += wsi->http.ah->frags[n].len;
|
|
|
|
n = wsi->http.ah->frags[n].nfrag;
|
2018-11-15 15:35:22 +08:00
|
|
|
|
2021-08-27 05:47:31 +01:00
|
|
|
if (n)
|
|
|
|
len++;
|
2018-11-15 15:35:22 +08:00
|
|
|
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
} while (n);
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,
|
2015-12-15 22:59:23 +08:00
|
|
|
enum lws_token_indexes h, int frag_idx)
|
|
|
|
{
|
|
|
|
int n = 0;
|
2017-07-19 04:39:14 +08:00
|
|
|
int f;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (!wsi->http.ah)
|
2017-07-19 04:39:14 +08:00
|
|
|
return -1;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
f = wsi->http.ah->frag_index[h];
|
2015-12-15 22:59:23 +08:00
|
|
|
|
2016-01-20 09:44:04 +08:00
|
|
|
if (!f)
|
|
|
|
return -1;
|
|
|
|
|
2015-12-15 22:59:23 +08:00
|
|
|
while (n < frag_idx) {
|
2018-04-27 15:20:56 +08:00
|
|
|
f = wsi->http.ah->frags[f].nfrag;
|
2015-12-15 22:59:23 +08:00
|
|
|
if (!f)
|
|
|
|
return -1;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (wsi->http.ah->frags[f].len >= len)
|
2024-09-28 06:01:36 +01:00
|
|
|
return -2;
|
2015-12-15 22:59:23 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
memcpy(dst, wsi->http.ah->data + wsi->http.ah->frags[f].offset,
|
|
|
|
wsi->http.ah->frags[f].len);
|
|
|
|
dst[wsi->http.ah->frags[f].len] = '\0';
|
2015-12-15 22:59:23 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
return wsi->http.ah->frags[f].len;
|
2015-12-15 22:59:23 +08:00
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
int lws_hdr_copy(struct lws *wsi, char *dst, int len,
|
2015-12-04 11:30:53 +08:00
|
|
|
enum lws_token_indexes h)
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
{
|
2021-08-27 05:47:31 +01:00
|
|
|
int toklen = lws_hdr_total_length(wsi, h), n, comma;
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
|
2018-10-09 10:29:42 +08:00
|
|
|
*dst = '\0';
|
|
|
|
if (!toklen)
|
|
|
|
return 0;
|
|
|
|
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
if (toklen >= len)
|
|
|
|
return -1;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (!wsi->http.ah)
|
2017-07-19 04:39:14 +08:00
|
|
|
return -1;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
n = wsi->http.ah->frag_index[h];
|
2014-04-02 19:45:42 +08:00
|
|
|
if (!n)
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
return 0;
|
|
|
|
do {
|
2021-01-19 20:45:31 +00:00
|
|
|
comma = (wsi->http.ah->frags[n].nfrag) ? 1 : 0;
|
|
|
|
|
2021-01-27 15:14:03 +00:00
|
|
|
if (h == WSI_TOKEN_HTTP_URI_ARGS)
|
2021-08-27 05:47:31 +01:00
|
|
|
lwsl_notice("%s: WSI_TOKEN_HTTP_URI_ARGS '%.*s'\n",
|
|
|
|
__func__, (int)wsi->http.ah->frags[n].len,
|
|
|
|
&wsi->http.ah->data[
|
|
|
|
wsi->http.ah->frags[n].offset]);
|
2018-11-15 15:35:22 +08:00
|
|
|
|
2021-01-27 15:14:03 +00:00
|
|
|
if (wsi->http.ah->frags[n].len + comma >= len) {
|
|
|
|
lwsl_notice("blowout len\n");
|
2017-11-02 08:10:41 +08:00
|
|
|
return -1;
|
2021-01-27 15:14:03 +00:00
|
|
|
}
|
2018-04-27 15:20:56 +08:00
|
|
|
strncpy(dst, &wsi->http.ah->data[wsi->http.ah->frags[n].offset],
|
|
|
|
wsi->http.ah->frags[n].len);
|
|
|
|
dst += wsi->http.ah->frags[n].len;
|
|
|
|
len -= wsi->http.ah->frags[n].len;
|
|
|
|
n = wsi->http.ah->frags[n].nfrag;
|
2018-10-14 11:38:08 +08:00
|
|
|
|
2021-08-27 05:47:31 +01:00
|
|
|
/*
|
|
|
|
* Note if you change this logic, take care about updating len
|
|
|
|
* and make sure lws_hdr_total_length() gives the same resulting
|
|
|
|
* length
|
|
|
|
*/
|
|
|
|
|
2021-01-19 20:45:31 +00:00
|
|
|
if (comma) {
|
2021-08-27 05:47:31 +01:00
|
|
|
if (h == WSI_TOKEN_HTTP_COOKIE ||
|
|
|
|
h == WSI_TOKEN_HTTP_SET_COOKIE)
|
2021-01-19 20:45:31 +00:00
|
|
|
*dst++ = ';';
|
|
|
|
else
|
2021-01-27 15:14:03 +00:00
|
|
|
if (h == WSI_TOKEN_HTTP_URI_ARGS)
|
|
|
|
*dst++ = '&';
|
|
|
|
else
|
|
|
|
*dst++ = ',';
|
2021-08-27 05:47:31 +01:00
|
|
|
len--;
|
2021-01-19 20:45:31 +00:00
|
|
|
}
|
2018-11-15 15:35:22 +08:00
|
|
|
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
} while (n);
|
2017-11-02 08:10:41 +08:00
|
|
|
*dst = '\0';
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
|
2021-01-27 15:14:03 +00:00
|
|
|
if (h == WSI_TOKEN_HTTP_URI_ARGS)
|
|
|
|
lwsl_err("%s: WSI_TOKEN_HTTP_URI_ARGS toklen %d\n", __func__, (int)toklen);
|
|
|
|
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
return toklen;
|
|
|
|
}
|
|
|
|
|
2019-02-26 17:18:24 +08:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
2020-01-02 08:32:23 +00:00
|
|
|
int
|
2019-02-26 17:18:24 +08:00
|
|
|
lws_hdr_custom_length(struct lws *wsi, const char *name, int nlen)
|
|
|
|
{
|
|
|
|
ah_data_idx_t ll;
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->http.ah || wsi->mux_substream)
|
2019-02-26 17:18:24 +08:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
ll = wsi->http.ah->unk_ll_head;
|
|
|
|
while (ll) {
|
|
|
|
if (ll >= wsi->http.ah->data_length)
|
|
|
|
return -1;
|
2019-09-11 06:34:52 +01:00
|
|
|
if (nlen == lws_ser_ru16be(
|
|
|
|
(uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]) &&
|
2020-12-12 06:21:40 +00:00
|
|
|
!strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], (unsigned int)nlen))
|
2019-09-11 06:34:52 +01:00
|
|
|
return lws_ser_ru16be(
|
|
|
|
(uint8_t *)&wsi->http.ah->data[ll + UHO_VLEN]);
|
2019-02-26 17:18:24 +08:00
|
|
|
|
2019-09-11 06:34:52 +01:00
|
|
|
ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]);
|
2019-02-26 17:18:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
int
|
2019-02-26 17:18:24 +08:00
|
|
|
lws_hdr_custom_copy(struct lws *wsi, char *dst, int len, const char *name,
|
|
|
|
int nlen)
|
|
|
|
{
|
|
|
|
ah_data_idx_t ll;
|
|
|
|
int n;
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->http.ah || wsi->mux_substream)
|
2019-02-26 17:18:24 +08:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
*dst = '\0';
|
|
|
|
|
|
|
|
ll = wsi->http.ah->unk_ll_head;
|
|
|
|
while (ll) {
|
|
|
|
if (ll >= wsi->http.ah->data_length)
|
|
|
|
return -1;
|
2019-09-11 06:34:52 +01:00
|
|
|
if (nlen == lws_ser_ru16be(
|
|
|
|
(uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]) &&
|
2020-12-12 06:21:40 +00:00
|
|
|
!strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], (unsigned int)nlen)) {
|
2019-09-11 06:34:52 +01:00
|
|
|
n = lws_ser_ru16be(
|
|
|
|
(uint8_t *)&wsi->http.ah->data[ll + UHO_VLEN]);
|
2019-02-26 17:18:24 +08:00
|
|
|
if (n + 1 > len)
|
|
|
|
return -1;
|
2020-12-12 06:21:40 +00:00
|
|
|
strncpy(dst, &wsi->http.ah->data[ll + UHO_NAME + (unsigned int)nlen], (unsigned int)n);
|
2019-02-26 17:18:24 +08:00
|
|
|
dst[n] = '\0';
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
2019-09-11 06:34:52 +01:00
|
|
|
ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]);
|
2019-02-26 17:18:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2021-08-28 06:18:32 +01:00
|
|
|
|
|
|
|
int
|
|
|
|
lws_hdr_custom_name_foreach(struct lws *wsi, lws_hdr_custom_fe_cb_t cb,
|
|
|
|
void *custom)
|
|
|
|
{
|
|
|
|
ah_data_idx_t ll;
|
|
|
|
|
|
|
|
if (!wsi->http.ah || wsi->mux_substream)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ll = wsi->http.ah->unk_ll_head;
|
|
|
|
|
|
|
|
while (ll) {
|
|
|
|
if (ll >= wsi->http.ah->data_length)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
cb(&wsi->http.ah->data[ll + UHO_NAME],
|
|
|
|
lws_ser_ru16be((uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]),
|
|
|
|
custom);
|
|
|
|
|
|
|
|
ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-02-26 17:18:24 +08:00
|
|
|
#endif
|
|
|
|
|
2015-12-04 11:08:32 +08:00
|
|
|
char *lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h)
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
{
|
|
|
|
int 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 (!wsi->http.ah)
|
|
|
|
return NULL;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
n = wsi->http.ah->frag_index[h];
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
if (!n)
|
|
|
|
return NULL;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
return wsi->http.ah->data + wsi->http.ah->frags[n].offset;
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
}
|
2013-01-18 01:55:48 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
static int LWS_WARN_UNUSED_RESULT
|
2016-01-21 10:57:39 +08:00
|
|
|
lws_pos_in_bounds(struct lws *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
|
|
|
if (!wsi->http.ah)
|
|
|
|
return -1;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (wsi->http.ah->pos <
|
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
|
|
|
(unsigned int)wsi->a.context->max_http_header_data)
|
2016-01-21 10:57:39 +08:00
|
|
|
return 0;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
if ((int)wsi->http.ah->pos >= (int)wsi->a.context->max_http_header_data - 1) {
|
2016-01-21 10:57:39 +08:00
|
|
|
lwsl_err("Ran out of header data space\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* with these tests everywhere, it should never be able to exceed
|
2017-09-23 12:55:21 +08:00
|
|
|
* the limit, only meet it
|
2016-01-21 10:57:39 +08:00
|
|
|
*/
|
2019-06-07 11:11:46 +01:00
|
|
|
lwsl_err("%s: pos %ld, limit %ld\n", __func__,
|
|
|
|
(unsigned long)wsi->http.ah->pos,
|
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
|
|
|
(unsigned long)wsi->a.context->max_http_header_data);
|
2016-01-21 10:57:39 +08:00
|
|
|
assert(0);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int LWS_WARN_UNUSED_RESULT
|
|
|
|
lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s)
|
2013-02-11 13:04:45 +08:00
|
|
|
{
|
2020-01-10 10:05:35 +00:00
|
|
|
if (!*s) {
|
|
|
|
/*
|
|
|
|
* If we get an empty string, then remove any entry for the
|
|
|
|
* header
|
|
|
|
*/
|
|
|
|
wsi->http.ah->frag_index[h] = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->nfrag++;
|
2018-08-16 19:10:32 +08:00
|
|
|
if (wsi->http.ah->nfrag == LWS_ARRAY_SIZE(wsi->http.ah->frags)) {
|
2013-02-11 17:13:32 +08:00
|
|
|
lwsl_warn("More hdr frags than we can deal with, dropping\n");
|
2013-02-11 13:04:45 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->frag_index[h] = wsi->http.ah->nfrag;
|
2013-02-11 13:04:45 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].offset = wsi->http.ah->pos;
|
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].len = 0;
|
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].nfrag = 0;
|
2013-02-11 13:04:45 +08:00
|
|
|
|
|
|
|
do {
|
2016-01-21 10:57:39 +08:00
|
|
|
if (lws_pos_in_bounds(wsi))
|
2013-02-11 13:04:45 +08:00
|
|
|
return -1;
|
2016-01-21 10:57:39 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->data[wsi->http.ah->pos++] = *s;
|
2013-02-11 13:04:45 +08:00
|
|
|
if (*s)
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].len++;
|
2013-02-11 13:04:45 +08:00
|
|
|
} while (*s++);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-20 16:56:06 +08:00
|
|
|
static int LWS_WARN_UNUSED_RESULT
|
|
|
|
issue_char(struct lws *wsi, unsigned char c)
|
2013-11-10 15:15:21 +08:00
|
|
|
{
|
2015-11-29 19:26:01 +08:00
|
|
|
unsigned short frag_len;
|
2015-12-15 21:15:58 +08:00
|
|
|
|
2016-01-21 10:57:39 +08:00
|
|
|
if (lws_pos_in_bounds(wsi))
|
2013-11-10 15:15:21 +08:00
|
|
|
return -1;
|
2014-06-29 00:25:19 -04:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
frag_len = wsi->http.ah->frags[wsi->http.ah->nfrag].len;
|
2015-12-15 21:15:58 +08:00
|
|
|
/*
|
|
|
|
* If we haven't hit the token limit, just copy the character into
|
|
|
|
* the header
|
|
|
|
*/
|
2018-08-14 08:00:25 +08:00
|
|
|
if (!wsi->http.ah->current_token_limit ||
|
|
|
|
frag_len < wsi->http.ah->current_token_limit) {
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->http.ah->data[wsi->http.ah->pos++] = (char)c;
|
2021-04-08 15:26:23 +01:00
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].len++;
|
2015-11-29 19:24:04 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-12-15 21:15:58 +08:00
|
|
|
|
|
|
|
/* Insert a null character when we *hit* the limit: */
|
2018-04-27 15:20:56 +08:00
|
|
|
if (frag_len == wsi->http.ah->current_token_limit) {
|
2016-01-21 10:57:39 +08:00
|
|
|
if (lws_pos_in_bounds(wsi))
|
2016-01-20 07:40:13 +08:00
|
|
|
return -1;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->data[wsi->http.ah->pos++] = '\0';
|
2019-06-07 11:11:46 +01:00
|
|
|
lwsl_warn("header %li exceeds limit %ld\n",
|
|
|
|
(long)wsi->http.ah->parser_state,
|
|
|
|
(long)wsi->http.ah->current_token_limit);
|
2015-12-15 21:15:58 +08:00
|
|
|
}
|
|
|
|
|
2015-11-29 19:24:04 +08:00
|
|
|
return 1;
|
2013-11-10 15:15:21 +08:00
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
int
|
|
|
|
lws_parse_urldecode(struct lws *wsi, uint8_t *_c)
|
|
|
|
{
|
2018-04-27 15:20:56 +08:00
|
|
|
struct allocated_headers *ah = wsi->http.ah;
|
2017-10-13 10:33:02 +08:00
|
|
|
unsigned int enc = 0;
|
|
|
|
uint8_t c = *_c;
|
|
|
|
|
2017-11-16 11:26:00 +08:00
|
|
|
// lwsl_notice("ah->ups %d\n", ah->ups);
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* PRIORITY 1
|
|
|
|
* special URI processing... convert %xx
|
|
|
|
*/
|
2017-11-16 11:26:00 +08:00
|
|
|
switch (ah->ues) {
|
2017-10-13 10:33:02 +08:00
|
|
|
case URIES_IDLE:
|
|
|
|
if (c == '%') {
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ues = URIES_SEEN_PERCENT;
|
2017-10-13 10:33:02 +08:00
|
|
|
goto swallow;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case URIES_SEEN_PERCENT:
|
2020-12-12 06:21:40 +00:00
|
|
|
if (char_to_hex((char)c) < 0)
|
2017-10-13 10:33:02 +08:00
|
|
|
/* illegal post-% char */
|
|
|
|
goto forbid;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->esc_stash = (char)c;
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ues = URIES_SEEN_PERCENT_H1;
|
2017-10-13 10:33:02 +08:00
|
|
|
goto swallow;
|
|
|
|
|
|
|
|
case URIES_SEEN_PERCENT_H1:
|
2020-12-12 06:21:40 +00:00
|
|
|
if (char_to_hex((char)c) < 0)
|
2017-10-13 10:33:02 +08:00
|
|
|
/* illegal post-% char */
|
|
|
|
goto forbid;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
*_c = (uint8_t)(unsigned int)((char_to_hex(ah->esc_stash) << 4) |
|
|
|
|
char_to_hex((char)c));
|
2017-10-13 10:33:02 +08:00
|
|
|
c = *_c;
|
|
|
|
enc = 1;
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ues = URIES_IDLE;
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* PRIORITY 2
|
|
|
|
* special URI processing...
|
|
|
|
* convert /.. or /... or /../ etc to /
|
|
|
|
* convert /./ to /
|
|
|
|
* convert // or /// etc to /
|
|
|
|
* leave /.dir or whatever alone
|
|
|
|
*/
|
|
|
|
|
2021-04-08 15:26:23 +01:00
|
|
|
if (!c && (!ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] ||
|
|
|
|
!ah->post_literal_equal)) {
|
|
|
|
/*
|
|
|
|
* Since user code is typically going to parse the path using
|
|
|
|
* NUL-terminated apis, it's too dangerous to allow NUL
|
|
|
|
* injection here.
|
|
|
|
*
|
|
|
|
* It's allowed in the urlargs, because the apis to access
|
|
|
|
* those only allow retreival with explicit length.
|
|
|
|
*/
|
|
|
|
lwsl_warn("%s: saw NUL outside of uri args\n", __func__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-11-16 11:26:00 +08:00
|
|
|
switch (ah->ups) {
|
2017-10-13 10:33:02 +08:00
|
|
|
case URIPS_IDLE:
|
2021-04-08 15:26:23 +01:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/* genuine delimiter */
|
|
|
|
if ((c == '&' || c == ';') && !enc) {
|
2018-06-19 12:30:10 +08:00
|
|
|
if (issue_char(wsi, '\0') < 0)
|
2017-10-13 10:33:02 +08:00
|
|
|
return -1;
|
2021-04-08 15:26:23 +01:00
|
|
|
/* don't account for it */
|
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
|
2017-10-13 10:33:02 +08:00
|
|
|
/* link to next fragment */
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->frags[ah->nfrag].nfrag = (uint8_t)(ah->nfrag + 1);
|
2017-10-13 10:33:02 +08:00
|
|
|
ah->nfrag++;
|
2018-08-16 19:10:32 +08:00
|
|
|
if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
|
2017-10-13 10:33:02 +08:00
|
|
|
goto excessive;
|
|
|
|
/* start next fragment after the & */
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->post_literal_equal = 0;
|
2018-06-19 12:30:10 +08:00
|
|
|
ah->frags[ah->nfrag].offset = ++ah->pos;
|
2017-10-13 10:33:02 +08:00
|
|
|
ah->frags[ah->nfrag].len = 0;
|
|
|
|
ah->frags[ah->nfrag].nfrag = 0;
|
|
|
|
goto swallow;
|
|
|
|
}
|
|
|
|
/* uriencoded = in the name part, disallow */
|
|
|
|
if (c == '=' && enc &&
|
|
|
|
ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] &&
|
2017-11-16 11:26:00 +08:00
|
|
|
!ah->post_literal_equal) {
|
2017-10-13 10:33:02 +08:00
|
|
|
c = '_';
|
|
|
|
*_c =c;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* after the real =, we don't care how many = */
|
|
|
|
if (c == '=' && !enc)
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->post_literal_equal = 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
/* + to space */
|
|
|
|
if (c == '+' && !enc) {
|
|
|
|
c = ' ';
|
|
|
|
*_c = c;
|
|
|
|
}
|
|
|
|
/* issue the first / always */
|
|
|
|
if (c == '/' && !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS])
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ups = URIPS_SEEN_SLASH;
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
case URIPS_SEEN_SLASH:
|
|
|
|
/* swallow subsequent slashes */
|
|
|
|
if (c == '/')
|
|
|
|
goto swallow;
|
|
|
|
/* track and swallow the first . after / */
|
|
|
|
if (c == '.') {
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ups = URIPS_SEEN_SLASH_DOT;
|
2017-10-13 10:33:02 +08:00
|
|
|
goto swallow;
|
|
|
|
}
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ups = URIPS_IDLE;
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
case URIPS_SEEN_SLASH_DOT:
|
|
|
|
/* swallow second . */
|
|
|
|
if (c == '.') {
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ups = URIPS_SEEN_SLASH_DOT_DOT;
|
2017-10-13 10:33:02 +08:00
|
|
|
goto swallow;
|
|
|
|
}
|
|
|
|
/* change /./ to / */
|
|
|
|
if (c == '/') {
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ups = URIPS_SEEN_SLASH;
|
2017-10-13 10:33:02 +08:00
|
|
|
goto swallow;
|
|
|
|
}
|
|
|
|
/* it was like /.dir ... regurgitate the . */
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ups = URIPS_IDLE;
|
2017-10-13 10:33:02 +08:00
|
|
|
if (issue_char(wsi, '.') < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case URIPS_SEEN_SLASH_DOT_DOT:
|
|
|
|
|
|
|
|
/* /../ or /..[End of URI] --> backup to last / */
|
|
|
|
if (c == '/' || c == '?') {
|
|
|
|
/*
|
|
|
|
* back up one dir level if possible
|
|
|
|
* safe against header fragmentation because
|
|
|
|
* the method URI can only be in 1 fragment
|
|
|
|
*/
|
|
|
|
if (ah->frags[ah->nfrag].len > 2) {
|
|
|
|
ah->pos--;
|
|
|
|
ah->frags[ah->nfrag].len--;
|
|
|
|
do {
|
|
|
|
ah->pos--;
|
|
|
|
ah->frags[ah->nfrag].len--;
|
|
|
|
} while (ah->frags[ah->nfrag].len > 1 &&
|
|
|
|
ah->data[ah->pos] != '/');
|
|
|
|
}
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ups = URIPS_SEEN_SLASH;
|
2017-10-13 10:33:02 +08:00
|
|
|
if (ah->frags[ah->nfrag].len > 1)
|
|
|
|
break;
|
|
|
|
goto swallow;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* /..[^/] ... regurgitate and allow */
|
|
|
|
|
|
|
|
if (issue_char(wsi, '.') < 0)
|
|
|
|
return -1;
|
|
|
|
if (issue_char(wsi, '.') < 0)
|
|
|
|
return -1;
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ups = URIPS_IDLE;
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '?' && !enc &&
|
2017-12-01 11:09:32 +08:00
|
|
|
!ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI args */
|
2017-11-16 11:26:00 +08:00
|
|
|
if (ah->ues != URIES_IDLE)
|
2017-10-13 10:33:02 +08:00
|
|
|
goto forbid;
|
|
|
|
|
|
|
|
/* seal off uri header */
|
|
|
|
if (issue_char(wsi, '\0') < 0)
|
|
|
|
return -1;
|
|
|
|
|
2021-04-08 15:26:23 +01:00
|
|
|
/* don't account for it */
|
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/* move to using WSI_TOKEN_HTTP_URI_ARGS */
|
|
|
|
ah->nfrag++;
|
2018-08-16 19:10:32 +08:00
|
|
|
if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
|
2017-10-13 10:33:02 +08:00
|
|
|
goto excessive;
|
2018-06-19 12:19:10 +08:00
|
|
|
ah->frags[ah->nfrag].offset = ++ah->pos;
|
2017-10-13 10:33:02 +08:00
|
|
|
ah->frags[ah->nfrag].len = 0;
|
|
|
|
ah->frags[ah->nfrag].nfrag = 0;
|
|
|
|
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->post_literal_equal = 0;
|
2017-10-13 10:33:02 +08:00
|
|
|
ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] = ah->nfrag;
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->ups = URIPS_IDLE;
|
2017-10-13 10:33:02 +08:00
|
|
|
goto swallow;
|
|
|
|
}
|
|
|
|
|
|
|
|
return LPUR_CONTINUE;
|
|
|
|
|
|
|
|
swallow:
|
|
|
|
return LPUR_SWALLOW;
|
|
|
|
|
|
|
|
forbid:
|
|
|
|
return LPUR_FORBID;
|
|
|
|
|
|
|
|
excessive:
|
|
|
|
return LPUR_EXCESSIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-10-13 10:33:02 +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-10-13 10:33:02 +08:00
|
|
|
WSI_TOKEN_CONNECT,
|
|
|
|
WSI_TOKEN_HEAD_URI,
|
|
|
|
};
|
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
/*
|
|
|
|
* possible returns:, -1 fail, 0 ok or 2, transition to raw
|
|
|
|
*/
|
|
|
|
|
2019-09-11 06:34:52 +01:00
|
|
|
lws_parser_return_t LWS_WARN_UNUSED_RESULT
|
2018-03-07 18:15:17 +08:00
|
|
|
lws_parse(struct lws *wsi, unsigned char *buf, int *len)
|
2010-11-08 20:20:42 +00:00
|
|
|
{
|
2018-04-27 15:20:56 +08:00
|
|
|
struct allocated_headers *ah = wsi->http.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
|
|
|
struct lws_context *context = wsi->a.context;
|
2017-10-13 10:33:02 +08:00
|
|
|
unsigned int n, m;
|
2018-03-07 18:15:17 +08:00
|
|
|
unsigned char c;
|
|
|
|
int r, pos;
|
2010-11-08 20:20:42 +00:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
assert(wsi->http.ah);
|
2016-01-26 20:56:56 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
do {
|
|
|
|
(*len)--;
|
|
|
|
c = *buf++;
|
2011-05-23 10:00:03 +01:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
switch (ah->parser_state) {
|
2019-02-26 17:18:24 +08:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
|
|
|
case WSI_TOKEN_UNKNOWN_VALUE_PART:
|
|
|
|
|
|
|
|
if (c == '\r')
|
|
|
|
break;
|
|
|
|
if (c == '\n') {
|
2019-09-11 06:34:52 +01:00
|
|
|
lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos + 2],
|
2020-12-12 06:21:40 +00:00
|
|
|
(uint16_t)(ah->pos - ah->unk_value_pos));
|
2019-02-26 17:18:24 +08:00
|
|
|
ah->parser_state = WSI_TOKEN_NAME_PART;
|
|
|
|
ah->unk_pos = 0;
|
|
|
|
ah->lextable_pos = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* trim leading whitespace */
|
|
|
|
if (ah->pos != ah->unk_value_pos ||
|
|
|
|
(c != ' ' && c != '\t')) {
|
|
|
|
|
|
|
|
if (lws_pos_in_bounds(wsi))
|
2019-09-11 06:34:52 +01:00
|
|
|
return LPR_FAIL;
|
2019-02-26 17:18:24 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->data[ah->pos++] = (char)c;
|
2019-02-26 17:18:24 +08:00
|
|
|
}
|
|
|
|
pos = ah->lextable_pos;
|
|
|
|
break;
|
|
|
|
#endif
|
2018-03-07 18:15:17 +08:00
|
|
|
default:
|
2010-11-08 20:20:42 +00:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
lwsl_parser("WSI_TOK_(%d) '%c'\n", ah->parser_state, c);
|
2010-11-13 10:03:47 +00:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
/* collect into malloc'd buffers */
|
|
|
|
/* optional initial space swallow */
|
|
|
|
if (!ah->frags[ah->frag_index[ah->parser_state]].len &&
|
|
|
|
c == ' ')
|
2015-01-10 19:01:52 -08:00
|
|
|
break;
|
2013-11-10 15:15:21 +08:00
|
|
|
|
2018-08-16 19:10:32 +08:00
|
|
|
for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
|
2018-03-07 18:15:17 +08:00
|
|
|
if (ah->parser_state == methods[m])
|
|
|
|
break;
|
2018-08-16 19:10:32 +08:00
|
|
|
if (m == LWS_ARRAY_SIZE(methods))
|
2018-03-07 18:15:17 +08:00
|
|
|
/* it was not any of the methods */
|
|
|
|
goto check_eol;
|
2013-11-10 15:15:21 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
/* special URI processing... end at space */
|
HTTP Version, Keep-alive support, No-copy POST
This is a squashed commit from https://github.com/andrew-canaday/libwebsockets,
dev/http_keepalive branch (strategies changed a few times, so the commit
history is clutteread). This branch is submitted for clarity, but the other
can be used as a reference or alternative.
* added **enum http_version** to track HTTP/1.0 vs HTTP/1.1 requests
* added **enum http_connection_type** to track keep-alive vs close
* replaced content_length_seen and body_index with **content_remain**
* removed **post_buffer** (see handshake.c modifications)
* removed post_buffer free
* switch state to WSI_TOKEN_SKIPPING after URI is complete to store version
* delete *spill* label (unused)
* add vars to track HTTP version and connection type
* HTTP version defaults to 1.0
* connection type defaults to 'close' for 1.0, keep-alive for 1.1
* additional checks in **cleanup:** label:
* if HTTP version string is present and valid, set enum val appropriately
* override connection default with the "Connection:" header, if present
* set state to WSI_STATE_HTTP_BODY if content_length > 0
* return 0 on HTTP requests, unless LWS_CALLBACK_HTTP indicates otherwise
* add vars to track remaining content_length and body chunk size
* re-arrange switch case order to facilitate creation of jump-table
* added new labels:
* **read_ok**: normal location reach on break from switch; just return 0
* **http_complete**: check for keep-alive + init state, mode, hdr table
* **http_new**: jump location for keep-alive when http_complete sees len>0
* after libwebsocket_parse, jump to one of those labels based on state
* POST body handling:
* don't bother iterating over input byte-by-byte or using memcpy
* just pass the relevant portion of the context->service_buffer to callback
2014-07-13 01:07:36 -04:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
if (c == ' ') {
|
|
|
|
/* enforce starting with / */
|
|
|
|
if (!ah->frags[ah->nfrag].len)
|
|
|
|
if (issue_char(wsi, '/') < 0)
|
2019-09-11 06:34:52 +01:00
|
|
|
return LPR_FAIL;
|
2018-03-07 18:15:17 +08:00
|
|
|
|
|
|
|
if (ah->ups == URIPS_SEEN_SLASH_DOT_DOT) {
|
|
|
|
/*
|
|
|
|
* back up one dir level if possible
|
2018-11-23 08:47:56 +08:00
|
|
|
* safe against header fragmentation
|
|
|
|
* because the method URI can only be
|
|
|
|
* in 1 fragment
|
2018-03-07 18:15:17 +08:00
|
|
|
*/
|
|
|
|
if (ah->frags[ah->nfrag].len > 2) {
|
2016-04-07 10:08:35 +08:00
|
|
|
ah->pos--;
|
|
|
|
ah->frags[ah->nfrag].len--;
|
2018-03-07 18:15:17 +08:00
|
|
|
do {
|
|
|
|
ah->pos--;
|
|
|
|
ah->frags[ah->nfrag].len--;
|
|
|
|
} while (ah->frags[ah->nfrag].len > 1 &&
|
|
|
|
ah->data[ah->pos] != '/');
|
|
|
|
}
|
2016-04-07 10:08:35 +08:00
|
|
|
}
|
2018-03-07 18:15:17 +08:00
|
|
|
|
|
|
|
/* begin parsing HTTP version: */
|
|
|
|
if (issue_char(wsi, '\0') < 0)
|
2019-09-11 06:34:52 +01:00
|
|
|
return LPR_FAIL;
|
2021-04-08 15:26:23 +01:00
|
|
|
/* don't account for it */
|
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
|
2018-03-07 18:15:17 +08:00
|
|
|
ah->parser_state = WSI_TOKEN_HTTP;
|
|
|
|
goto start_fragment;
|
2016-04-07 10:08:35 +08:00
|
|
|
}
|
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
r = lws_parse_urldecode(wsi, &c);
|
|
|
|
switch (r) {
|
|
|
|
case LPUR_CONTINUE:
|
|
|
|
break;
|
|
|
|
case LPUR_SWALLOW:
|
|
|
|
goto swallow;
|
|
|
|
case LPUR_FORBID:
|
|
|
|
goto forbid;
|
|
|
|
case LPUR_EXCESSIVE:
|
|
|
|
goto excessive;
|
|
|
|
default:
|
2018-11-29 08:47:49 +08:00
|
|
|
return LPR_FAIL;
|
2018-03-07 18:15:17 +08:00
|
|
|
}
|
2014-07-19 06:58:53 +08:00
|
|
|
check_eol:
|
2018-03-07 18:15:17 +08:00
|
|
|
/* bail at EOL */
|
|
|
|
if (ah->parser_state != WSI_TOKEN_CHALLENGE &&
|
2020-06-30 17:50:01 +01:00
|
|
|
(c == '\x0d' || c == '\x0a')) {
|
2018-03-07 18:15:17 +08:00
|
|
|
if (ah->ues != URIES_IDLE)
|
|
|
|
goto forbid;
|
|
|
|
|
2020-06-30 17:50:01 +01:00
|
|
|
if (c == '\x0a') {
|
|
|
|
/* broken peer */
|
|
|
|
ah->parser_state = WSI_TOKEN_NAME_PART;
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->unk_pos = 0;
|
|
|
|
ah->lextable_pos = 0;
|
2020-06-30 17:50:01 +01:00
|
|
|
} else
|
|
|
|
ah->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
|
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
c = '\0';
|
|
|
|
lwsl_parser("*\n");
|
|
|
|
}
|
2014-07-19 06:58:53 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (unsigned int)issue_char(wsi, c);
|
2018-03-07 18:15:17 +08:00
|
|
|
if ((int)n < 0)
|
2018-11-29 08:47:49 +08:00
|
|
|
return LPR_FAIL;
|
2018-03-07 18:15:17 +08:00
|
|
|
if (n > 0)
|
|
|
|
ah->parser_state = WSI_TOKEN_SKIPPING;
|
2021-04-08 15:26:23 +01:00
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* Explicit zeroes are legal in URI ARGS.
|
|
|
|
* They can only exist as a safety terminator
|
|
|
|
* after the valid part of the token contents
|
|
|
|
* for other types.
|
|
|
|
*/
|
|
|
|
if (!c && ah->parser_state != WSI_TOKEN_HTTP_URI_ARGS)
|
|
|
|
/* don't account for safety terminator */
|
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
|
|
|
|
}
|
2014-08-19 18:34:31 +08:00
|
|
|
|
2013-11-10 15:15:21 +08:00
|
|
|
swallow:
|
2018-03-07 18:15:17 +08:00
|
|
|
/* per-protocol end of headers management */
|
2011-01-18 15:39:02 +00:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
if (ah->parser_state == WSI_TOKEN_CHALLENGE)
|
|
|
|
goto set_parsing_complete;
|
|
|
|
break;
|
2011-05-23 10:00:03 +01:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
/* collecting and checking a name part */
|
|
|
|
case WSI_TOKEN_NAME_PART:
|
2019-06-07 11:11:46 +01:00
|
|
|
lwsl_parser("WSI_TOKEN_NAME_PART '%c' 0x%02X "
|
|
|
|
"(role=0x%lx) "
|
|
|
|
"wsi->lextable_pos=%d\n", c, c,
|
|
|
|
(unsigned long)lwsi_role(wsi),
|
2018-03-07 18:15:17 +08:00
|
|
|
ah->lextable_pos);
|
|
|
|
|
2020-06-30 17:50:01 +01:00
|
|
|
if (!ah->unk_pos && c == '\x0a')
|
|
|
|
/* broken peer */
|
|
|
|
goto set_parsing_complete;
|
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
if (c >= 'A' && c <= 'Z')
|
2020-12-12 06:21:40 +00:00
|
|
|
c = (unsigned char)(c + 'a' - 'A');
|
2019-02-26 17:18:24 +08:00
|
|
|
/*
|
|
|
|
* ...in case it's an unknown header, speculatively
|
|
|
|
* store it as the name comes in. If we recognize it as
|
|
|
|
* a known header, we'll snip this.
|
|
|
|
*/
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream && !ah->unk_pos) {
|
2019-02-26 17:18:24 +08:00
|
|
|
ah->unk_pos = ah->pos;
|
2020-06-30 17:49:14 +01:00
|
|
|
|
2020-06-26 07:34:27 +01:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
2019-02-26 17:18:24 +08:00
|
|
|
/*
|
|
|
|
* Prepare new unknown header linked-list entry
|
|
|
|
*
|
|
|
|
* - 16-bit BE: name part length
|
|
|
|
* - 16-bit BE: value part length
|
|
|
|
* - 32-bit BE: data offset of next, or 0
|
|
|
|
*/
|
|
|
|
for (n = 0; n < 8; n++)
|
|
|
|
if (!lws_pos_in_bounds(wsi))
|
|
|
|
ah->data[ah->pos++] = 0;
|
|
|
|
#endif
|
2020-06-26 07:34:27 +01:00
|
|
|
}
|
2019-02-26 17:18:24 +08:00
|
|
|
|
|
|
|
if (lws_pos_in_bounds(wsi))
|
2019-09-11 06:34:52 +01:00
|
|
|
return LPR_FAIL;
|
2019-02-26 17:18:24 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->data[ah->pos++] = (char)c;
|
2018-03-07 18:15:17 +08:00
|
|
|
pos = ah->lextable_pos;
|
|
|
|
|
2019-02-26 17:18:24 +08:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream && pos < 0 && c == ':') {
|
2019-11-04 10:54:50 +00:00
|
|
|
#if defined(_DEBUG)
|
|
|
|
char dotstar[64];
|
|
|
|
int uhlen;
|
|
|
|
#endif
|
|
|
|
|
2019-02-26 17:18:24 +08:00
|
|
|
/*
|
|
|
|
* process unknown headers
|
|
|
|
*
|
|
|
|
* register us in the unknown hdr ll
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!ah->unk_ll_head)
|
|
|
|
ah->unk_ll_head = ah->unk_pos;
|
|
|
|
|
|
|
|
if (ah->unk_ll_tail)
|
2019-09-11 06:34:52 +01:00
|
|
|
lws_ser_wu32be(
|
|
|
|
(uint8_t *)&ah->data[ah->unk_ll_tail + UHO_LL],
|
2019-02-26 17:18:24 +08:00
|
|
|
ah->unk_pos);
|
|
|
|
|
|
|
|
ah->unk_ll_tail = ah->unk_pos;
|
|
|
|
|
2019-11-04 10:54:50 +00:00
|
|
|
#if defined(_DEBUG)
|
2020-12-12 06:21:40 +00:00
|
|
|
uhlen = (int)(ah->pos - (ah->unk_pos + UHO_NAME));
|
2019-11-04 10:54:50 +00:00
|
|
|
lws_strnncpy(dotstar,
|
|
|
|
&ah->data[ah->unk_pos + UHO_NAME],
|
|
|
|
uhlen, sizeof(dotstar));
|
|
|
|
lwsl_debug("%s: unk header %d '%s'\n",
|
|
|
|
__func__,
|
|
|
|
ah->pos - (ah->unk_pos + UHO_NAME),
|
|
|
|
dotstar);
|
|
|
|
#endif
|
2019-02-26 17:18:24 +08:00
|
|
|
|
|
|
|
/* set the unknown header name part length */
|
|
|
|
|
2019-09-11 06:34:52 +01:00
|
|
|
lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos],
|
2020-12-12 06:21:40 +00:00
|
|
|
(uint16_t)((ah->pos - ah->unk_pos) - UHO_NAME));
|
2019-02-26 17:18:24 +08:00
|
|
|
|
|
|
|
ah->unk_value_pos = ah->pos;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* collect whatever's coming for the unknown header
|
|
|
|
* argument until the next CRLF
|
|
|
|
*/
|
|
|
|
ah->parser_state = WSI_TOKEN_UNKNOWN_VALUE_PART;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (pos < 0)
|
|
|
|
break;
|
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
while (1) {
|
2020-02-28 15:50:15 +00:00
|
|
|
if (lextable_h1[pos] & (1 << 7)) {
|
2018-11-23 08:47:56 +08:00
|
|
|
/* 1-byte, fail on mismatch */
|
2020-02-28 15:50:15 +00:00
|
|
|
if ((lextable_h1[pos] & 0x7f) != c) {
|
2018-03-07 18:15:17 +08:00
|
|
|
nope:
|
|
|
|
ah->lextable_pos = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* fall thru */
|
|
|
|
pos++;
|
2020-02-28 15:50:15 +00:00
|
|
|
if (lextable_h1[pos] == FAIL_CHAR)
|
2018-03-07 18:15:17 +08:00
|
|
|
goto nope;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->lextable_pos = (int16_t)pos;
|
2018-03-07 18:15:17 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-11-08 20:20:42 +00:00
|
|
|
|
2020-02-28 15:50:15 +00:00
|
|
|
if (lextable_h1[pos] == FAIL_CHAR)
|
2018-03-07 18:15:17 +08:00
|
|
|
goto nope;
|
|
|
|
|
|
|
|
/* b7 = 0, end or 3-byte */
|
2020-02-28 15:50:15 +00:00
|
|
|
if (lextable_h1[pos] < FAIL_CHAR) {
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream) {
|
2019-10-10 16:37:38 +01:00
|
|
|
/*
|
|
|
|
* We hit a terminal marker, so
|
|
|
|
* we recognized this header...
|
|
|
|
* drop the speculative name
|
|
|
|
* part storage
|
|
|
|
*/
|
|
|
|
ah->pos = ah->unk_pos;
|
|
|
|
ah->unk_pos = 0;
|
|
|
|
}
|
2020-06-26 07:34:27 +01:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->lextable_pos = (int16_t)pos;
|
2015-01-10 19:01:52 -08:00
|
|
|
break;
|
|
|
|
}
|
2018-03-07 18:15:17 +08:00
|
|
|
|
2020-02-28 15:50:15 +00:00
|
|
|
if (lextable_h1[pos] == c) { /* goto */
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->lextable_pos = (int16_t)(pos +
|
2020-02-28 15:50:15 +00:00
|
|
|
(lextable_h1[pos + 1]) +
|
2020-12-12 06:21:40 +00:00
|
|
|
(lextable_h1[pos + 2] << 8));
|
2018-03-07 18:15:17 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fall thru goto */
|
|
|
|
pos += 3;
|
|
|
|
/* continue */
|
|
|
|
}
|
|
|
|
|
2013-02-12 12:52:39 +08:00
|
|
|
/*
|
2019-02-26 17:18:24 +08:00
|
|
|
* If it's h1, server needs to be on the look out for
|
|
|
|
* unknown methods...
|
2013-02-12 12:52:39 +08:00
|
|
|
*/
|
2018-04-11 13:39:42 +08:00
|
|
|
if (ah->lextable_pos < 0 && lwsi_role_h1(wsi) &&
|
|
|
|
lwsi_role_server(wsi)) {
|
2019-02-26 17:18:24 +08:00
|
|
|
/*
|
|
|
|
* this is not a header we know about... did
|
|
|
|
* we get a valid method (GET, POST etc)
|
|
|
|
* already, or is this the bogus method?
|
|
|
|
*/
|
2018-08-16 19:10:32 +08:00
|
|
|
for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
|
2018-03-07 18:15:17 +08:00
|
|
|
if (ah->frag_index[methods[m]]) {
|
|
|
|
/*
|
2019-02-26 17:18:24 +08:00
|
|
|
* already had the method
|
2018-03-07 18:15:17 +08:00
|
|
|
*/
|
2019-02-26 17:18:24 +08:00
|
|
|
#if !defined(LWS_WITH_CUSTOM_HEADERS)
|
2018-03-07 18:15:17 +08:00
|
|
|
ah->parser_state = WSI_TOKEN_SKIPPING;
|
2019-02-26 17:18:24 +08:00
|
|
|
#endif
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->mux_substream)
|
2019-10-10 16:37:38 +01:00
|
|
|
ah->parser_state = WSI_TOKEN_SKIPPING;
|
2018-03-07 18:15:17 +08:00
|
|
|
break;
|
|
|
|
}
|
2019-02-26 17:18:24 +08:00
|
|
|
|
2019-10-10 16:37:38 +01:00
|
|
|
if (m != LWS_ARRAY_SIZE(methods)) {
|
2019-02-26 17:18:24 +08:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
|
|
|
/*
|
|
|
|
* We have the method, this is just an
|
|
|
|
* unknown header then
|
|
|
|
*/
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream)
|
2019-10-10 16:37:38 +01:00
|
|
|
goto unknown_hdr;
|
|
|
|
else
|
|
|
|
break;
|
2019-02-26 17:18:24 +08:00
|
|
|
#else
|
2018-11-29 08:47:49 +08:00
|
|
|
break;
|
2019-02-26 17:18:24 +08:00
|
|
|
#endif
|
2019-10-10 16:37:38 +01:00
|
|
|
}
|
2018-11-29 08:47:49 +08:00
|
|
|
/*
|
2019-02-26 17:18:24 +08:00
|
|
|
* ...it's an unknown http method from a client
|
|
|
|
* in fact, it cannot be valid http.
|
|
|
|
*
|
|
|
|
* Are we set up to transition to another role
|
|
|
|
* in these cases?
|
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 (lws_check_opt(wsi->a.vhost->options,
|
2018-11-29 08:47:49 +08:00
|
|
|
LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG)) {
|
|
|
|
lwsl_notice("%s: http fail fallback\n",
|
|
|
|
__func__);
|
|
|
|
/* transition to other role */
|
|
|
|
return LPR_DO_FALLBACK;
|
2018-03-07 18:15:17 +08:00
|
|
|
}
|
2018-11-29 08:47:49 +08:00
|
|
|
|
|
|
|
lwsl_info("Unknown method - dropping\n");
|
|
|
|
goto forbid;
|
2018-03-07 18:15:17 +08:00
|
|
|
}
|
|
|
|
if (ah->lextable_pos < 0) {
|
2020-06-30 17:49:14 +01:00
|
|
|
/*
|
|
|
|
* It's not a header that lws knows about...
|
|
|
|
*/
|
2019-02-26 17:18:24 +08:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream)
|
2019-10-10 16:37:38 +01:00
|
|
|
goto unknown_hdr;
|
|
|
|
#endif
|
2019-02-26 17:18:24 +08:00
|
|
|
/*
|
|
|
|
* ...otherwise for a client, let him ignore
|
|
|
|
* unknown headers coming from the server
|
|
|
|
*/
|
2018-03-07 18:15:17 +08:00
|
|
|
ah->parser_state = WSI_TOKEN_SKIPPING;
|
|
|
|
break;
|
2015-01-30 12:04:43 +00:00
|
|
|
}
|
2015-04-07 08:19:30 +08:00
|
|
|
|
2020-02-28 15:50:15 +00:00
|
|
|
if (lextable_h1[ah->lextable_pos] < FAIL_CHAR) {
|
2018-03-07 18:15:17 +08:00
|
|
|
/* terminal state */
|
2013-02-04 09:24:18 +08:00
|
|
|
|
2020-02-28 15:50:15 +00:00
|
|
|
n = ((unsigned int)lextable_h1[ah->lextable_pos] << 8) |
|
|
|
|
lextable_h1[ah->lextable_pos + 1];
|
2013-01-18 01:55:48 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
lwsl_parser("known hdr %d\n", n);
|
2018-08-16 19:10:32 +08:00
|
|
|
for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
|
2018-03-07 18:15:17 +08:00
|
|
|
if (n == methods[m] &&
|
|
|
|
ah->frag_index[methods[m]]) {
|
|
|
|
lwsl_warn("Duplicated method\n");
|
2018-11-29 08:47:49 +08:00
|
|
|
return LPR_FAIL;
|
2018-03-07 18:15:17 +08:00
|
|
|
}
|
2013-02-12 13:10:19 +08:00
|
|
|
|
2020-06-30 17:49:14 +01:00
|
|
|
if (!wsi->mux_substream) {
|
|
|
|
/*
|
|
|
|
* Whether we are collecting unknown names or not,
|
|
|
|
* if we matched an internal header we can dispense
|
|
|
|
* with the header name part we were keeping
|
|
|
|
*/
|
|
|
|
ah->pos = ah->unk_pos;
|
|
|
|
ah->unk_pos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(LWS_ROLE_WS)
|
2018-03-07 18:15:17 +08:00
|
|
|
/*
|
|
|
|
* WSORIGIN is protocol equiv to ORIGIN,
|
|
|
|
* JWebSocket likes to send it, map to ORIGIN
|
|
|
|
*/
|
|
|
|
if (n == WSI_TOKEN_SWORIGIN)
|
|
|
|
n = WSI_TOKEN_ORIGIN;
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
2012-04-03 17:02:20 +02:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->parser_state = (uint8_t)
|
2018-11-23 08:47:56 +08:00
|
|
|
(WSI_TOKEN_GET_URI + n);
|
2018-03-07 18:15:17 +08:00
|
|
|
ah->ups = URIPS_IDLE;
|
2014-06-29 01:34:24 -04:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
if (context->token_limits)
|
|
|
|
ah->current_token_limit = context->
|
2018-11-23 08:47:56 +08:00
|
|
|
token_limits->token_limit[
|
|
|
|
ah->parser_state];
|
2018-03-07 18:15:17 +08:00
|
|
|
else
|
|
|
|
ah->current_token_limit =
|
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->max_http_header_data;
|
2014-06-29 01:34:24 -04:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
if (ah->parser_state == WSI_TOKEN_CHALLENGE)
|
|
|
|
goto set_parsing_complete;
|
2011-01-23 16:50:33 +00:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
goto start_fragment;
|
|
|
|
}
|
|
|
|
break;
|
2012-04-05 10:31:48 +08:00
|
|
|
|
2019-02-26 17:18:24 +08:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
|
|
|
unknown_hdr:
|
|
|
|
//ah->parser_state = WSI_TOKEN_SKIPPING;
|
|
|
|
//break;
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream)
|
2019-10-10 16:37:38 +01:00
|
|
|
break;
|
2019-02-26 17:18:24 +08:00
|
|
|
#endif
|
|
|
|
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
start_fragment:
|
2018-03-07 18:15:17 +08:00
|
|
|
ah->nfrag++;
|
2015-12-15 22:57:19 +08:00
|
|
|
excessive:
|
2018-08-16 19:10:32 +08:00
|
|
|
if (ah->nfrag == LWS_ARRAY_SIZE(ah->frags)) {
|
2018-03-07 18:15:17 +08:00
|
|
|
lwsl_warn("More hdr frags than we can deal with\n");
|
2018-11-29 08:47:49 +08:00
|
|
|
return LPR_FAIL;
|
2018-03-07 18:15:17 +08:00
|
|
|
}
|
2010-11-08 20:20:42 +00:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
ah->frags[ah->nfrag].offset = ah->pos;
|
|
|
|
ah->frags[ah->nfrag].len = 0;
|
|
|
|
ah->frags[ah->nfrag].nfrag = 0;
|
|
|
|
ah->frags[ah->nfrag].flags = 2;
|
|
|
|
|
|
|
|
n = ah->frag_index[ah->parser_state];
|
|
|
|
if (!n) { /* first fragment */
|
|
|
|
ah->frag_index[ah->parser_state] = ah->nfrag;
|
|
|
|
ah->hdr_token_idx = ah->parser_state;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* continuation */
|
|
|
|
while (ah->frags[n].nfrag)
|
|
|
|
n = ah->frags[n].nfrag;
|
|
|
|
ah->frags[n].nfrag = ah->nfrag;
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
if (issue_char(wsi, ' ') < 0)
|
2018-11-29 08:47:49 +08:00
|
|
|
return LPR_FAIL;
|
improve minilex use external parsing header
Clean up minilex
Move the header output to stdout
Introduce lexfile.h as the header output
Use lexfile.h in both minilex itself and lws
Add the following header support
"Accept:",
"If-Modified-Since:",
"Accept-Encoding:",
"Accept-Language:",
"Pragma:",
"Cache-Control:",
"Authorization:",
"Cookie:",
"Content-Type:",
"Date:",
"Range:",
"Referer:"
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-11-09 10:09:09 +08:00
|
|
|
break;
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
/* skipping arg part of a name we didn't recognize */
|
|
|
|
case WSI_TOKEN_SKIPPING:
|
|
|
|
lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
|
2010-11-13 10:03:47 +00:00
|
|
|
|
2020-06-30 17:50:01 +01:00
|
|
|
if (c == '\x0a') {
|
|
|
|
/* broken peer */
|
|
|
|
ah->parser_state = WSI_TOKEN_NAME_PART;
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->unk_pos = 0;
|
|
|
|
ah->lextable_pos = 0;
|
2020-06-30 17:50:01 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
if (c == '\x0d')
|
|
|
|
ah->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
|
|
|
|
break;
|
2013-11-19 13:38:16 +01:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
case WSI_TOKEN_SKIPPING_SAW_CR:
|
|
|
|
lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
|
|
|
|
if (ah->ues != URIES_IDLE)
|
|
|
|
goto forbid;
|
|
|
|
if (c == '\x0a') {
|
|
|
|
ah->parser_state = WSI_TOKEN_NAME_PART;
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->unk_pos = 0;
|
|
|
|
ah->lextable_pos = 0;
|
2018-03-07 18:15:17 +08:00
|
|
|
} else
|
|
|
|
ah->parser_state = WSI_TOKEN_SKIPPING;
|
|
|
|
break;
|
|
|
|
/* we're done, ignore anything else */
|
2013-02-04 09:09:19 +08:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
case WSI_PARSING_COMPLETE:
|
|
|
|
lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
|
|
|
|
break;
|
|
|
|
}
|
2013-11-19 13:38:16 +01:00
|
|
|
|
2018-03-07 18:15:17 +08:00
|
|
|
} while (*len);
|
2010-11-13 10:03:47 +00:00
|
|
|
|
2018-11-29 08:47:49 +08:00
|
|
|
return LPR_OK;
|
2013-02-04 09:09:19 +08:00
|
|
|
|
|
|
|
set_parsing_complete:
|
2017-11-16 11:26:00 +08:00
|
|
|
if (ah->ues != URIES_IDLE)
|
2016-04-07 10:08:35 +08:00
|
|
|
goto forbid;
|
2018-09-02 14:35:37 +08:00
|
|
|
|
replace per header mallocs with single malloc 3 level struct
This big patch replaces the malloc / realloc per header
approach used until now with a single three-level struct
that gets malloc'd during the header union phase and freed
in one go when we transition to a different union phase.
It's more expensive in that we malloc a bit more than 4Kbytes,
but it's a lot cheaper in terms of malloc, frees, heap fragmentation,
no reallocs, nothing to configure. It also moves from arrays of
pointers (8 bytes on x86_64) to unsigned short offsets into the
data array, (2 bytes on all platforms).
The 3-level thing is all in one struct
- array indexed by the header enum, pointing to first "fragment" index
(ie, header type to fragment lookup, or 0 for none)
- array of fragments indexes, enough for 2 x the number of known headers
(fragment array... note that fragments can point to a "next"
fragment if the same header is spread across multiple entries)
- linear char array where the known header payload gets written
(fragments point into null-terminated strings stored in here,
only the known header content is stored)
http headers can legally be split over multiple headers of the same
name which should be concatenated. This scheme does not linearly
conatenate them but uses a linked list in the fragment structs to
link them. There are apis to get the total length and copy out a
linear, concatenated version to a buffer.
Signed-off-by: Andy Green <andy.green@linaro.org>
2013-02-10 18:02:31 +08:00
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
|
2020-02-28 10:31:04 +00:00
|
|
|
#if defined(LWS_ROLE_WS)
|
2020-03-27 19:10:40 +00:00
|
|
|
const char *pv = lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION);
|
|
|
|
if (pv)
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->rx_frame_type = (char)atoi(pv);
|
2013-02-04 09:09:19 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
lwsl_parser("v%02d hdrs done\n", wsi->rx_frame_type);
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
2013-02-06 15:15:25 +09:00
|
|
|
}
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->parser_state = WSI_PARSING_COMPLETE;
|
2013-02-11 21:43:41 +08:00
|
|
|
wsi->hdr_parsing_completed = 1;
|
2013-02-04 09:09:19 +08:00
|
|
|
|
2018-11-29 08:47:49 +08:00
|
|
|
return LPR_OK;
|
2016-04-07 10:08:35 +08:00
|
|
|
|
|
|
|
forbid:
|
2020-01-30 13:19:11 +00:00
|
|
|
lwsl_info(" forbidding on uri sanitation\n");
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2016-04-07 10:08:35 +08:00
|
|
|
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
|
2019-08-18 05:04:15 +01:00
|
|
|
#endif
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-11-29 08:47:49 +08:00
|
|
|
return LPR_FORBIDDEN;
|
2010-11-08 20:20:42 +00:00
|
|
|
}
|
|
|
|
|
2020-07-10 12:48:10 +01:00
|
|
|
int
|
|
|
|
lws_http_cookie_get(struct lws *wsi, const char *name, char *buf,
|
|
|
|
size_t *max_len)
|
|
|
|
{
|
2021-01-19 20:45:31 +00:00
|
|
|
size_t max = *max_len, bl = strlen(name);
|
2020-07-10 12:48:10 +01:00
|
|
|
char *p, *bo = buf;
|
2021-01-19 20:45:31 +00:00
|
|
|
int n;
|
2020-07-10 12:48:10 +01:00
|
|
|
|
|
|
|
n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE);
|
2021-01-19 20:45:31 +00:00
|
|
|
if ((unsigned int)n < bl + 1)
|
2020-07-10 12:48:10 +01:00
|
|
|
return 1;
|
|
|
|
|
2021-01-19 20:45:31 +00:00
|
|
|
/*
|
|
|
|
* This can come to us two ways, in ah fragments (h2) or as a single
|
|
|
|
* semicolon-delimited string (h1)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(LWS_ROLE_H2)
|
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_METHOD)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The h2 way...
|
|
|
|
*/
|
|
|
|
|
|
|
|
int f = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_COOKIE];
|
|
|
|
size_t fl;
|
|
|
|
|
|
|
|
while (f) {
|
|
|
|
p = wsi->http.ah->data + wsi->http.ah->frags[f].offset;
|
|
|
|
fl = (size_t)wsi->http.ah->frags[f].len;
|
|
|
|
if (fl >= bl + 1 &&
|
|
|
|
p[bl] == '=' &&
|
|
|
|
!memcmp(p, name, bl)) {
|
|
|
|
fl -= bl + 1;
|
|
|
|
if (max - 1 < fl)
|
|
|
|
fl = max - 1;
|
|
|
|
if (fl)
|
|
|
|
memcpy(buf, p + bl + 1, fl);
|
|
|
|
*max_len = fl;
|
|
|
|
buf[fl] = '\0';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
f = wsi->http.ah->frags[f].nfrag;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The h1 way...
|
|
|
|
*/
|
|
|
|
|
2020-07-10 12:48:10 +01:00
|
|
|
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COOKIE);
|
|
|
|
if (!p)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
p += bl;
|
2021-01-19 20:45:31 +00:00
|
|
|
n -= (int)bl;
|
2021-12-02 09:18:23 +00:00
|
|
|
while (n-- > 0) {
|
2020-12-12 06:21:40 +00:00
|
|
|
if (*p == '=' && !memcmp(p - bl, name, (unsigned int)bl)) {
|
2020-07-10 12:48:10 +01:00
|
|
|
p++;
|
|
|
|
while (*p != ';' && n-- && max) {
|
|
|
|
*buf++ = *p++;
|
|
|
|
max--;
|
|
|
|
}
|
|
|
|
if (!max)
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
*buf = '\0';
|
2020-12-12 06:21:40 +00:00
|
|
|
*max_len = lws_ptr_diff_size_t(buf, bo);
|
2020-07-10 12:48:10 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2020-07-11 07:16:16 +01:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_JOSE)
|
|
|
|
|
|
|
|
#define MAX_JWT_SIZE 1024
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_jwt_get_http_cookie_validate_jwt(struct lws *wsi,
|
|
|
|
struct lws_jwt_sign_set_cookie *i,
|
|
|
|
char *out, size_t *out_len)
|
|
|
|
{
|
|
|
|
char temp[MAX_JWT_SIZE * 2];
|
|
|
|
size_t cml = *out_len;
|
|
|
|
const char *cp;
|
|
|
|
|
|
|
|
/* first use out to hold the encoded JWT */
|
|
|
|
|
|
|
|
if (lws_http_cookie_get(wsi, i->cookie_name, out, out_len)) {
|
2020-11-06 20:25:36 +00:00
|
|
|
lwsl_debug("%s: cookie %s not provided\n", __func__,
|
2020-07-11 07:16:16 +01:00
|
|
|
i->cookie_name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* decode the JWT into temp */
|
|
|
|
|
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_jwt_signed_validate(wsi->a.context, i->jwk, i->alg, out,
|
2020-07-11 07:16:16 +01:00
|
|
|
*out_len, temp, sizeof(temp), out, &cml)) {
|
2020-11-06 20:25:36 +00:00
|
|
|
lwsl_info("%s: jwt validation failed\n", __func__);
|
2020-07-11 07:16:16 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy out the decoded JWT payload into out, overwriting the
|
|
|
|
* original encoded JWT taken from the cookie (that has long ago been
|
|
|
|
* translated into allocated buffers in the JOSE object)
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (lws_jwt_token_sanity(out, cml, i->iss, i->aud, i->csrf_in,
|
|
|
|
i->sub, sizeof(i->sub),
|
|
|
|
&i->expiry_unix_time)) {
|
|
|
|
lwsl_notice("%s: jwt sanity failed\n", __func__);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If he's interested in his private JSON part, point him to that in
|
|
|
|
* the args struct (it's pointing to the data in out
|
|
|
|
*/
|
|
|
|
|
|
|
|
cp = lws_json_simple_find(out, cml, "\"ext\":", &i->extra_json_len);
|
|
|
|
if (cp)
|
|
|
|
i->extra_json = cp;
|
|
|
|
|
2020-11-06 20:25:36 +00:00
|
|
|
if (!cp)
|
2020-07-11 07:16:16 +01:00
|
|
|
lwsl_notice("%s: no ext JWT payload\n", __func__);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_jwt_sign_token_set_http_cookie(struct lws *wsi,
|
|
|
|
const struct lws_jwt_sign_set_cookie *i,
|
|
|
|
uint8_t **p, uint8_t *end)
|
|
|
|
{
|
|
|
|
char plain[MAX_JWT_SIZE + 1], temp[MAX_JWT_SIZE * 2], csrf[17];
|
|
|
|
size_t pl = sizeof(plain);
|
|
|
|
unsigned long long ull;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a 16-char random csrf token with the same lifetime as the JWT
|
|
|
|
*/
|
|
|
|
|
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_hex_random(wsi->a.context, csrf, sizeof(csrf));
|
2020-07-11 07:16:16 +01:00
|
|
|
ull = lws_now_secs();
|
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_jwt_sign_compact(wsi->a.context, i->jwk, i->alg, plain, &pl,
|
2020-07-11 07:16:16 +01:00
|
|
|
temp, sizeof(temp),
|
|
|
|
"{\"iss\":\"%s\",\"aud\":\"%s\","
|
|
|
|
"\"iat\":%llu,\"nbf\":%llu,\"exp\":%llu,"
|
|
|
|
"\"csrf\":\"%s\",\"sub\":\"%s\"%s%s%s}",
|
|
|
|
i->iss, i->aud, ull, ull - 60,
|
|
|
|
ull + i->expiry_unix_time,
|
|
|
|
csrf, i->sub,
|
|
|
|
i->extra_json ? ",\"ext\":{" : "",
|
|
|
|
i->extra_json ? i->extra_json : "",
|
|
|
|
i->extra_json ? "}" : "")) {
|
|
|
|
lwsl_err("%s: failed to create JWT\n", __func__);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There's no point the browser holding on to a JWT beyond the JWT's
|
|
|
|
* expiry time, so set it to be the same.
|
|
|
|
*/
|
|
|
|
|
|
|
|
n = lws_snprintf(temp, sizeof(temp), "__Host-%s=%s;"
|
|
|
|
"HttpOnly;"
|
|
|
|
"Secure;"
|
|
|
|
"SameSite=strict;"
|
|
|
|
"Path=/;"
|
|
|
|
"Max-Age=%lu",
|
|
|
|
i->cookie_name, plain, i->expiry_unix_time);
|
|
|
|
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SET_COOKIE,
|
|
|
|
(uint8_t *)temp, n, p, end)) {
|
|
|
|
lwsl_err("%s: failed to add JWT cookie header\n", __func__);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|