2014-10-08 12:00:53 +08:00
|
|
|
/*
|
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
2014-10-08 12:00:53 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to
|
|
|
|
* deal in the Software without restriction, including without limitation the
|
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2014-10-08 12:00:53 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
2014-10-08 12:00:53 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
* IN THE SOFTWARE.
|
2014-10-08 12:00:53 +08:00
|
|
|
*/
|
|
|
|
|
2019-08-15 10:49:52 +01:00
|
|
|
#include "private-lib-core.h"
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* bitmap of control messages that are valid to receive for each http2 state
|
|
|
|
*/
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
static const uint16_t http2_rx_validity[] = {
|
|
|
|
/* LWS_H2S_IDLE */
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_SETTINGS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PRIORITY) |
|
|
|
|
// (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE)| /* ignore */
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_HEADERS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_CONTINUATION),
|
|
|
|
/* LWS_H2S_RESERVED_LOCAL */
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_SETTINGS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_RST_STREAM) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PRIORITY) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE),
|
|
|
|
/* LWS_H2S_RESERVED_REMOTE */
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_SETTINGS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_HEADERS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_CONTINUATION) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_RST_STREAM) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PRIORITY),
|
|
|
|
/* LWS_H2S_OPEN */
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_DATA) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_HEADERS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PRIORITY) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_RST_STREAM) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_SETTINGS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PUSH_PROMISE) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PING) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_GOAWAY) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_CONTINUATION),
|
|
|
|
/* LWS_H2S_HALF_CLOSED_REMOTE */
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_SETTINGS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PRIORITY) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_RST_STREAM),
|
|
|
|
/* LWS_H2S_HALF_CLOSED_LOCAL */
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_DATA) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_HEADERS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PRIORITY) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_RST_STREAM) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_SETTINGS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PUSH_PROMISE) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PING) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_GOAWAY) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_CONTINUATION),
|
|
|
|
/* LWS_H2S_CLOSED */
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_SETTINGS) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_PRIORITY) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |
|
|
|
|
(1 << LWS_H2_FRAME_TYPE_RST_STREAM),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *preface = "PRI * HTTP/2.0\x0d\x0a\x0d\x0aSM\x0d\x0a\x0d\x0a";
|
|
|
|
|
|
|
|
static const char * const h2_state_names[] = {
|
|
|
|
"LWS_H2S_IDLE",
|
|
|
|
"LWS_H2S_RESERVED_LOCAL",
|
|
|
|
"LWS_H2S_RESERVED_REMOTE",
|
|
|
|
"LWS_H2S_OPEN",
|
|
|
|
"LWS_H2S_HALF_CLOSED_REMOTE",
|
|
|
|
"LWS_H2S_HALF_CLOSED_LOCAL",
|
|
|
|
"LWS_H2S_CLOSED",
|
|
|
|
};
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static const char * const h2_setting_names[] = {
|
|
|
|
"",
|
|
|
|
"H2SET_HEADER_TABLE_SIZE",
|
|
|
|
"H2SET_ENABLE_PUSH",
|
|
|
|
"H2SET_MAX_CONCURRENT_STREAMS",
|
|
|
|
"H2SET_INITIAL_WINDOW_SIZE",
|
|
|
|
"H2SET_MAX_FRAME_SIZE",
|
|
|
|
"H2SET_MAX_HEADER_LIST_SIZE",
|
2018-03-11 11:26:06 +08:00
|
|
|
"reserved",
|
|
|
|
"H2SET_ENABLE_CONNECT_PROTOCOL"
|
2017-10-13 10:33:02 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_h2_dump_settings(struct http2_settings *set)
|
|
|
|
{
|
|
|
|
int n;
|
2014-10-09 16:57:47 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
for (n = 1; n < H2SET_COUNT; n++)
|
|
|
|
lwsl_notice(" %30s: %10d\n", h2_setting_names[n], set->s[n]);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
void
|
|
|
|
lws_h2_dump_settings(struct http2_settings *set)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
#endif
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2019-09-18 13:09:32 +01:00
|
|
|
struct lws_h2_protocol_send *
|
2018-03-27 09:17:19 +08:00
|
|
|
lws_h2_new_pps(enum lws_h2_protocol_send_type type)
|
|
|
|
{
|
|
|
|
struct lws_h2_protocol_send *pps = lws_malloc(sizeof(*pps), "pps");
|
|
|
|
|
|
|
|
if (pps)
|
|
|
|
pps->type = type;
|
|
|
|
|
|
|
|
return pps;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
void lws_h2_init(struct lws *wsi)
|
2014-10-08 12:00:53 +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
|
|
|
wsi->h2.h2n->our_set = wsi->a.vhost->h2.set;
|
2019-12-26 02:35:41 +00:00
|
|
|
wsi->h2.h2n->peer_set = lws_h2_defaults;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-04-03 12:00:46 +08:00
|
|
|
void
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_state(struct lws *wsi, enum lws_h2_states s)
|
|
|
|
{
|
|
|
|
if (!wsi)
|
|
|
|
return;
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: state %s -> %s\n", __func__, lws_wsi_tag(wsi),
|
2017-12-01 11:09:32 +08:00
|
|
|
h2_state_names[wsi->h2.h2_state],
|
2017-10-13 10:33:02 +08:00
|
|
|
h2_state_names[s]);
|
2017-10-22 10:38:43 +08:00
|
|
|
|
|
|
|
(void)h2_state_names;
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.h2_state = (uint8_t)s;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
int
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_h2_update_peer_txcredit(struct lws *wsi, unsigned int sid, int bump)
|
2019-12-26 02:35:41 +00:00
|
|
|
{
|
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
|
|
|
struct lws_h2_protocol_send *pps;
|
|
|
|
|
|
|
|
assert(wsi);
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
if (!bump)
|
|
|
|
return 0;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
if (sid == (unsigned int)-1)
|
2019-12-26 02:35:41 +00:00
|
|
|
sid = wsi->mux.my_sid;
|
|
|
|
|
|
|
|
lwsl_info("%s: sid %d: bump %d -> %d\n", __func__, sid, bump,
|
2020-01-16 07:16:01 +00:00
|
|
|
(int)wsi->txc.peer_tx_cr_est + bump);
|
2019-12-26 02:35:41 +00:00
|
|
|
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
pps->u.update_window.sid = (unsigned int)sid;
|
|
|
|
pps->u.update_window.credit = (unsigned int)bump;
|
2019-12-26 02:35:41 +00:00
|
|
|
wsi->txc.peer_tx_cr_est += bump;
|
|
|
|
|
|
|
|
lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
|
|
|
|
|
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
pps->u.update_window.sid = 0;
|
2020-12-12 06:21:40 +00:00
|
|
|
pps->u.update_window.credit = (unsigned int)bump;
|
2019-12-26 02:35:41 +00:00
|
|
|
nwsi->txc.peer_tx_cr_est += bump;
|
|
|
|
|
|
|
|
lws_wsi_txc_describe(&nwsi->txc, __func__, nwsi->mux.my_sid);
|
|
|
|
|
|
|
|
lws_pps_schedule(nwsi, pps);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_h2_get_peer_txcredit_estimate(struct lws *wsi)
|
|
|
|
{
|
|
|
|
lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
|
|
|
|
return (int)wsi->txc.peer_tx_cr_est;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_h2_update_peer_txcredit_thresh(struct lws *wsi, unsigned int sid, int threshold, int bump)
|
2019-12-26 02:35:41 +00:00
|
|
|
{
|
|
|
|
if (wsi->txc.peer_tx_cr_est > threshold)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return lws_h2_update_peer_txcredit(wsi, sid, bump);
|
|
|
|
}
|
|
|
|
|
2021-04-04 04:06:24 +01:00
|
|
|
/* cx + vh lock */
|
|
|
|
|
|
|
|
static struct lws *
|
|
|
|
__lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
|
|
|
|
unsigned int sid)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws *nwsi = lws_get_network_wsi(parent_wsi);
|
2017-12-01 11:09:32 +08:00
|
|
|
struct lws_h2_netconn *h2n = nwsi->h2.h2n;
|
2021-02-05 13:08:41 +00:00
|
|
|
char tmp[50], tmp1[50];
|
|
|
|
unsigned int n, b = 0;
|
2021-01-19 14:19:12 +00:00
|
|
|
struct lws *wsi;
|
2021-02-05 13:08:41 +00:00
|
|
|
const char *p;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_context_assert_lock_held(vh->context);
|
|
|
|
lws_vhost_assert_lock_held(vh);
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* The identifier of a newly established stream MUST be numerically
|
|
|
|
* greater than all streams that the initiating endpoint has opened or
|
|
|
|
* reserved. This governs streams that are opened using a HEADERS frame
|
|
|
|
* and streams that are reserved using PUSH_PROMISE. An endpoint that
|
|
|
|
* receives an unexpected stream identifier MUST respond with a
|
|
|
|
* connection error (Section 5.4.1) of type PROTOCOL_ERROR.
|
|
|
|
*/
|
|
|
|
if (sid <= h2n->highest_sid_opened) {
|
2019-10-10 16:37:38 +01:00
|
|
|
lwsl_info("%s: tried to open lower sid %d (%d)\n", __func__,
|
2019-11-05 21:00:45 +00:00
|
|
|
sid, (int)h2n->highest_sid_opened);
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, "Bad sid");
|
2014-10-08 12:00:53 +08:00
|
|
|
return NULL;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
/* no more children allowed by parent */
|
2019-12-23 11:31:57 +00:00
|
|
|
if (parent_wsi->mux.child_count + 1 >
|
2019-12-26 02:35:41 +00:00
|
|
|
parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_notice("reached concurrent stream limit\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
2021-02-05 13:08:41 +00:00
|
|
|
|
|
|
|
n = 0;
|
|
|
|
p = &parent_wsi->lc.gutag[1];
|
|
|
|
do {
|
|
|
|
if (*p == '|') {
|
|
|
|
b++;
|
|
|
|
if (b == 3)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
tmp1[n++] = *p++;
|
|
|
|
} while (b < 3 && n < sizeof(tmp1) - 2);
|
|
|
|
tmp1[n] = '\0';
|
|
|
|
lws_snprintf(tmp, sizeof(tmp), "h2_sid%u_(%s)", sid, tmp1);
|
|
|
|
wsi = lws_create_new_server_wsi(vh, parent_wsi->tsi, tmp);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!wsi) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_notice("new server wsi failed (%s)\n", lws_vh_tag(vh));
|
2017-10-13 10:33:02 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2021-06-28 11:51:44 +01:00
|
|
|
if (lwsi_role_server(parent_wsi)) {
|
2021-01-06 15:08:22 +00:00
|
|
|
lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mth_srv);
|
2021-06-28 11:51:44 +01:00
|
|
|
}
|
2021-01-06 15:08:22 +00:00
|
|
|
#endif
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->highest_sid_opened = sid;
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
lws_wsi_mux_insert(wsi, parent_wsi, sid);
|
2020-04-06 13:22:01 +01:00
|
|
|
if (sid >= h2n->highest_sid)
|
|
|
|
h2n->highest_sid = sid + 2;
|
2019-12-23 11:31:57 +00:00
|
|
|
|
|
|
|
wsi->mux_substream = 1;
|
|
|
|
wsi->seen_nonpseudoheader = 0;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->txc.tx_cr = (int32_t)nwsi->h2.h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
|
2019-12-26 02:35:41 +00:00
|
|
|
wsi->txc.peer_tx_cr_est =
|
2020-12-12 06:21:40 +00:00
|
|
|
(int32_t)nwsi->h2.h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE];
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
|
|
|
lwsi_set_role(wsi, lwsi_role(parent_wsi));
|
2015-12-14 08:52:03 +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
|
|
|
wsi->a.protocol = &vh->protocols[0];
|
2016-04-23 09:36:18 +08:00
|
|
|
if (lws_ensure_user_space(wsi))
|
2017-10-13 10:33:02 +08:00
|
|
|
goto bail1;
|
|
|
|
|
2020-07-27 10:03:12 +01:00
|
|
|
#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
|
|
|
|
if (lws_adopt_ss_server_accept(wsi))
|
|
|
|
goto bail1;
|
|
|
|
#endif
|
|
|
|
|
2019-09-18 13:09:32 +01:00
|
|
|
/* get the ball rolling */
|
|
|
|
lws_validity_confirmed(wsi);
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s new ch %s, sid %d, usersp=%p\n", __func__,
|
|
|
|
lws_wsi_tag(parent_wsi), lws_wsi_tag(wsi), sid, wsi->user_space);
|
2019-12-26 02:35:41 +00:00
|
|
|
|
|
|
|
lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
|
|
|
|
lws_wsi_txc_describe(&nwsi->txc, __func__, 0);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
return wsi;
|
2016-04-23 09:36:18 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
bail1:
|
|
|
|
/* undo the insert */
|
2019-12-23 11:31:57 +00:00
|
|
|
parent_wsi->mux.child_list = wsi->mux.sibling_list;
|
|
|
|
parent_wsi->mux.child_count--;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (wsi->user_space)
|
|
|
|
lws_free_set_NULL(wsi->user_space);
|
|
|
|
vh->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
|
2021-04-04 04:06:24 +01:00
|
|
|
__lws_vhost_unbind_wsi(wsi);
|
2016-04-23 09:36:18 +08:00
|
|
|
lws_free(wsi);
|
|
|
|
|
|
|
|
return NULL;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
struct lws *
|
|
|
|
lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi)
|
|
|
|
{
|
|
|
|
struct lws *nwsi = lws_get_network_wsi(parent_wsi);
|
|
|
|
|
|
|
|
/* no more children allowed by parent */
|
2019-12-23 11:31:57 +00:00
|
|
|
if (parent_wsi->mux.child_count + 1 >
|
2019-12-26 02:35:41 +00:00
|
|
|
parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
|
2018-03-27 09:17:19 +08:00
|
|
|
lwsl_notice("reached concurrent stream limit\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sid is set just before issuing the headers, ensuring monoticity */
|
|
|
|
|
|
|
|
wsi->seen_nonpseudoheader = 0;
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2019-12-23 11:31:57 +00:00
|
|
|
wsi->client_mux_substream = 1;
|
2018-11-12 15:24:42 +08:00
|
|
|
#endif
|
2018-03-27 09:17:19 +08:00
|
|
|
wsi->h2.initialized = 1;
|
|
|
|
|
2020-05-04 08:26:48 +01:00
|
|
|
#if 0
|
|
|
|
/* only assign sid at header send time when we know it */
|
2020-01-30 13:19:11 +00:00
|
|
|
if (!wsi->mux.my_sid) {
|
|
|
|
wsi->mux.my_sid = nwsi->h2.h2n->highest_sid;
|
|
|
|
nwsi->h2.h2n->highest_sid += 2;
|
|
|
|
}
|
2020-05-04 08:26:48 +01:00
|
|
|
#endif
|
2020-01-30 13:19:11 +00:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: binding wsi %s to sid %d (next %d)\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), (int)wsi->mux.my_sid, (int)nwsi->h2.h2n->highest_sid);
|
2020-04-06 13:22:01 +01:00
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
lws_wsi_mux_insert(wsi, parent_wsi, wsi->mux.my_sid);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->txc.tx_cr = (int32_t)nwsi->h2.h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
|
|
|
|
wsi->txc.peer_tx_cr_est = (int32_t)
|
2019-12-26 02:35:41 +00:00
|
|
|
nwsi->h2.h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE];
|
|
|
|
|
|
|
|
lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
if (lws_ensure_user_space(wsi))
|
|
|
|
goto bail1;
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS,
|
|
|
|
&role_ops_h2);
|
2018-04-02 11:55:17 +08:00
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
|
|
|
|
return wsi;
|
|
|
|
|
|
|
|
bail1:
|
|
|
|
/* undo the insert */
|
2019-12-23 11:31:57 +00:00
|
|
|
parent_wsi->mux.child_list = wsi->mux.sibling_list;
|
|
|
|
parent_wsi->mux.child_count--;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
if (wsi->user_space)
|
|
|
|
lws_free_set_NULL(wsi->user_space);
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.protocol->callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
|
2018-03-27 09:17:19 +08:00
|
|
|
lws_free(wsi);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-12-19 09:13:24 +00:00
|
|
|
int
|
|
|
|
lws_h2_issue_preface(struct lws *wsi)
|
2018-03-27 09:17:19 +08:00
|
|
|
{
|
|
|
|
struct lws_h2_netconn *h2n = wsi->h2.h2n;
|
|
|
|
struct lws_h2_protocol_send *pps;
|
|
|
|
|
2021-04-10 06:45:21 +01:00
|
|
|
if (!h2n) {
|
|
|
|
lwsl_warn("%s: no valid h2n\n", __func__);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
if (h2n->sent_preface)
|
|
|
|
return 1;
|
|
|
|
|
2021-01-01 09:01:09 +00:00
|
|
|
lwsl_debug("%s: %s: fd %d\n", __func__, lws_wsi_tag(wsi), (int)wsi->desc.sockfd);
|
2020-12-19 09:13:24 +00:00
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
if (lws_issue_raw(wsi, (uint8_t *)preface, strlen(preface)) !=
|
|
|
|
(int)strlen(preface))
|
|
|
|
return 1;
|
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
h2n->sent_preface = 1;
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS,
|
|
|
|
&role_ops_h2);
|
2018-04-02 11:55:17 +08:00
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
h2n->count = 0;
|
2019-12-26 02:35:41 +00:00
|
|
|
wsi->txc.tx_cr = 65535;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* we must send a settings frame
|
|
|
|
*/
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
lwsl_info("%s: h2 client sending settings\n", __func__);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
void
|
|
|
|
lws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pps)
|
|
|
|
{
|
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
2017-12-01 11:09:32 +08:00
|
|
|
struct lws_h2_netconn *h2n = nwsi->h2.h2n;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2022-02-01 07:59:41 +00:00
|
|
|
if (!h2n) {
|
|
|
|
lwsl_warn("%s: null h2n\n", __func__);
|
|
|
|
lws_free(pps);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
pps->next = h2n->pps;
|
|
|
|
h2n->pps = pps;
|
|
|
|
lws_rx_flow_control(wsi, LWS_RXFLOW_REASON_APPLIES_DISABLE |
|
|
|
|
LWS_RXFLOW_REASON_H2_PPS_PENDING);
|
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_h2_goaway(struct lws *wsi, uint32_t err, const char *reason)
|
|
|
|
{
|
2017-12-01 11:09:32 +08:00
|
|
|
struct lws_h2_netconn *h2n = wsi->h2.h2n;
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws_h2_protocol_send *pps;
|
|
|
|
|
|
|
|
if (h2n->type == LWS_H2_FRAME_TYPE_COUNT)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_GOAWAY);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: ERR 0x%x, '%s'\n", __func__, lws_wsi_tag(wsi), (int)err, reason);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
pps->u.ga.err = err;
|
2017-10-16 12:52:32 +08:00
|
|
|
pps->u.ga.highest_sid = h2n->highest_sid;
|
2018-03-12 09:28:26 +08:00
|
|
|
lws_strncpy(pps->u.ga.str, reason, sizeof(pps->u.ga.str));
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
|
|
|
|
h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason)
|
|
|
|
{
|
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
2017-12-01 11:09:32 +08:00
|
|
|
struct lws_h2_netconn *h2n = nwsi->h2.h2n;
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws_h2_protocol_send *pps;
|
|
|
|
|
2018-09-04 08:06:46 +08:00
|
|
|
if (!h2n)
|
|
|
|
return 0;
|
|
|
|
|
2019-11-04 21:19:53 +00:00
|
|
|
if (!wsi->h2_stream_carries_ws && h2n->type == LWS_H2_FRAME_TYPE_COUNT)
|
2017-10-13 10:33:02 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_RST_STREAM);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_info("%s: RST_STREAM 0x%x, sid %d, REASON '%s'\n", __func__,
|
|
|
|
(int)err, wsi->mux.my_sid, reason);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
pps->u.rs.sid = wsi->mux.my_sid;
|
2017-10-13 10:33:02 +08:00
|
|
|
pps->u.rs.err = err;
|
2019-11-04 21:19:53 +00:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
|
|
|
|
h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
|
|
|
|
lws_h2_state(wsi, LWS_H2_STATE_CLOSED);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
int
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
|
2019-12-26 02:35:41 +00:00
|
|
|
unsigned char *buf, int len)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
2014-10-08 12:00:53 +08:00
|
|
|
unsigned int a, b;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
if (!len)
|
|
|
|
return 0;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (len < LWS_H2_SETTINGS_LEN)
|
2014-10-08 12:00:53 +08:00
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
while (len >= LWS_H2_SETTINGS_LEN) {
|
2020-12-12 06:21:40 +00:00
|
|
|
a = (unsigned int)((buf[0] << 8) | buf[1]);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!a || a >= H2SET_COUNT)
|
|
|
|
goto skip;
|
2020-12-12 06:21:40 +00:00
|
|
|
b = (unsigned int)(buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5]);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
switch (a) {
|
|
|
|
case H2SET_HEADER_TABLE_SIZE:
|
|
|
|
break;
|
|
|
|
case H2SET_ENABLE_PUSH:
|
|
|
|
if (b > 1) {
|
|
|
|
lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
|
2017-10-16 12:52:32 +08:00
|
|
|
"ENABLE_PUSH invalid arg");
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case H2SET_MAX_CONCURRENT_STREAMS:
|
|
|
|
break;
|
|
|
|
case H2SET_INITIAL_WINDOW_SIZE:
|
|
|
|
if (b > 0x7fffffff) {
|
|
|
|
lws_h2_goaway(nwsi, H2_ERR_FLOW_CONTROL_ERROR,
|
2017-10-16 12:52:32 +08:00
|
|
|
"Inital Window beyond max");
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2019-06-05 05:04:17 +01:00
|
|
|
|
2019-10-03 07:58:24 -07:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2019-07-13 14:50:58 -07:00
|
|
|
#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
|
2019-10-03 07:58:24 -07:00
|
|
|
if (
|
|
|
|
#else
|
|
|
|
if (wsi->flags & LCCSCF_H2_QUIRK_OVERFLOWS_TXCR &&
|
|
|
|
#endif
|
|
|
|
b == 0x7fffffff) {
|
|
|
|
b >>= 4;
|
|
|
|
|
2019-06-05 05:04:17 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* In addition to changing the flow-control window for
|
|
|
|
* streams that are not yet active, a SETTINGS frame
|
|
|
|
* can alter the initial flow-control window size for
|
|
|
|
* streams with active flow-control windows (that is,
|
|
|
|
* streams in the "open" or "half-closed (remote)"
|
|
|
|
* state). When the value of
|
|
|
|
* SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver
|
|
|
|
* MUST adjust the size of all stream flow-control
|
|
|
|
* windows that it maintains by the difference between
|
|
|
|
* the new value and the old value.
|
|
|
|
*/
|
|
|
|
|
|
|
|
lws_start_foreach_ll(struct lws *, w,
|
2019-12-23 11:31:57 +00:00
|
|
|
nwsi->mux.child_list) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("%s: adi child tc cr %d +%d -> %d",
|
2020-01-16 07:16:01 +00:00
|
|
|
__func__, (int)w->txc.tx_cr,
|
2019-12-26 02:35:41 +00:00
|
|
|
b - (unsigned int)settings->s[a],
|
2020-12-12 06:21:40 +00:00
|
|
|
(int)(w->txc.tx_cr + (int)b -
|
|
|
|
(int)settings->s[a]));
|
|
|
|
w->txc.tx_cr += (int)b - (int)settings->s[a];
|
2019-12-26 02:35:41 +00:00
|
|
|
if (w->txc.tx_cr > 0 &&
|
|
|
|
w->txc.tx_cr <=
|
2018-11-23 08:47:56 +08:00
|
|
|
(int32_t)(b - settings->s[a]))
|
2020-01-02 08:32:23 +00:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_callback_on_writable(w);
|
2019-12-23 11:31:57 +00:00
|
|
|
} lws_end_foreach_ll(w, mux.sibling_list);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
case H2SET_MAX_FRAME_SIZE:
|
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 (b < wsi->a.vhost->h2.set.s[H2SET_MAX_FRAME_SIZE]) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Frame size < initial");
|
|
|
|
return 1;
|
|
|
|
}
|
2019-07-07 12:19:54 +01:00
|
|
|
if (b > 0x00ffffff) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Settings Frame size above max");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case H2SET_MAX_HEADER_LIST_SIZE:
|
|
|
|
break;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
settings->s[a] = b;
|
|
|
|
lwsl_info("http2 settings %d <- 0x%x\n", a, b);
|
|
|
|
skip:
|
|
|
|
len -= LWS_H2_SETTINGS_LEN;
|
|
|
|
buf += LWS_H2_SETTINGS_LEN;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
if (len)
|
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_dump_settings(settings);
|
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/* RFC7640 Sect 6.9
|
|
|
|
*
|
|
|
|
* The WINDOW_UPDATE frame can be specific to a stream or to the entire
|
|
|
|
* connection. In the former case, the frame's stream identifier
|
|
|
|
* indicates the affected stream; in the latter, the value "0" indicates
|
|
|
|
* that the entire connection is the subject of the frame.
|
|
|
|
*
|
|
|
|
* ...
|
|
|
|
*
|
|
|
|
* Two flow-control windows are applicable: the stream flow-control
|
|
|
|
* window and the connection flow-control window. The sender MUST NOT
|
|
|
|
* send a flow-controlled frame with a length that exceeds the space
|
|
|
|
* available in either of the flow-control windows advertised by the
|
|
|
|
* receiver. Frames with zero length with the END_STREAM flag set (that
|
|
|
|
* is, an empty DATA frame) MAY be sent if there is no available space
|
|
|
|
* in either flow-control window.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_h2_tx_cr_get(struct lws *wsi)
|
2014-10-18 12:23:05 +08:00
|
|
|
{
|
2019-12-26 02:35:41 +00:00
|
|
|
int c = wsi->txc.tx_cr;
|
2019-10-16 15:08:25 +01:00
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream && !nwsi->upgraded_to_http2)
|
2017-10-13 10:33:02 +08:00
|
|
|
return ~0x80000000;
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info ("%s: %s: own tx credit %d: nwsi credit %d\n",
|
|
|
|
__func__, lws_wsi_tag(wsi), c, (int)nwsi->txc.tx_cr);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
if (nwsi->txc.tx_cr < c)
|
|
|
|
c = nwsi->txc.tx_cr;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (c < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return c;
|
2014-10-18 12:23:05 +08:00
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
void
|
|
|
|
lws_h2_tx_cr_consume(struct lws *wsi, int consumed)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
wsi->txc.tx_cr -= consumed;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (nwsi != wsi)
|
2019-12-26 02:35:41 +00:00
|
|
|
nwsi->txc.tx_cr -= consumed;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int lws_h2_frame_write(struct lws *wsi, int type, int flags,
|
|
|
|
unsigned int sid, unsigned int len, unsigned char *buf)
|
|
|
|
{
|
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
|
|
|
unsigned char *p = &buf[-LWS_H2_FRAME_HEADER_LENGTH];
|
2014-10-08 12:00:53 +08:00
|
|
|
int n;
|
|
|
|
|
2018-03-11 11:26:06 +08:00
|
|
|
//if (wsi->h2_stream_carries_ws)
|
|
|
|
// lwsl_hexdump_level(LLL_NOTICE, buf, len);
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
*p++ = (uint8_t)(len >> 16);
|
|
|
|
*p++ = (uint8_t)(len >> 8);
|
|
|
|
*p++ = (uint8_t)len;
|
|
|
|
*p++ = (uint8_t)type;
|
|
|
|
*p++ = (uint8_t)flags;
|
|
|
|
*p++ = (uint8_t)(sid >> 24);
|
|
|
|
*p++ = (uint8_t)(sid >> 16);
|
|
|
|
*p++ = (uint8_t)(sid >> 8);
|
|
|
|
*p++ = (uint8_t)sid;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: %s (eff %s). typ %d, fl 0x%x, sid=%d, len=%d, "
|
|
|
|
"txcr=%d, nwsi->txcr=%d\n", __func__, lws_wsi_tag(wsi),
|
|
|
|
lws_wsi_tag(nwsi), type, flags,
|
2020-01-16 07:16:01 +00:00
|
|
|
sid, len, (int)wsi->txc.tx_cr, (int)nwsi->txc.tx_cr);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (type == LWS_H2_FRAME_TYPE_DATA) {
|
2019-12-26 02:35:41 +00:00
|
|
|
if (wsi->txc.tx_cr < (int)len)
|
2020-12-12 06:21:40 +00:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: sending payload len %d"
|
|
|
|
" but tx_cr only %d!\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), len, (int)wsi->txc.tx_cr);
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_h2_tx_cr_consume(wsi, (int)len);
|
2014-10-29 09:39:08 +08:00
|
|
|
}
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
n = lws_issue_raw(nwsi, &buf[-LWS_H2_FRAME_HEADER_LENGTH],
|
|
|
|
len + LWS_H2_FRAME_HEADER_LENGTH);
|
|
|
|
if (n < 0)
|
|
|
|
return n;
|
|
|
|
|
|
|
|
if (n >= LWS_H2_FRAME_HEADER_LENGTH)
|
|
|
|
return n - LWS_H2_FRAME_HEADER_LENGTH;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
static void lws_h2_set_bin(struct lws *wsi, int n, unsigned char *buf)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
2020-12-12 06:21:40 +00:00
|
|
|
*buf++ = (uint8_t)(n >> 8);
|
|
|
|
*buf++ = (uint8_t)n;
|
|
|
|
*buf++ = (uint8_t)(wsi->h2.h2n->our_set.s[n] >> 24);
|
|
|
|
*buf++ = (uint8_t)(wsi->h2.h2n->our_set.s[n] >> 16);
|
|
|
|
*buf++ = (uint8_t)(wsi->h2.h2n->our_set.s[n] >> 8);
|
|
|
|
*buf = (uint8_t)wsi->h2.h2n->our_set.s[n];
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
|
|
|
|
2018-04-17 11:43:20 +08:00
|
|
|
/* we get called on the network connection */
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
int lws_h2_do_pps_send(struct lws *wsi)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
2017-12-01 11:09:32 +08:00
|
|
|
struct lws_h2_netconn *h2n = wsi->h2.h2n;
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws_h2_protocol_send *pps = NULL;
|
|
|
|
struct lws *cwsi;
|
|
|
|
uint8_t set[LWS_PRE + 64], *p = &set[LWS_PRE], *q;
|
2018-03-27 09:17:19 +08:00
|
|
|
int n, m = 0, flags = 0;
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!h2n)
|
|
|
|
return 1;
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/* get the oldest pps */
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_start_foreach_llp(struct lws_h2_protocol_send **, pps1, h2n->pps) {
|
|
|
|
if ((*pps1)->next == NULL) { /* we are the oldest in the list */
|
|
|
|
pps = *pps1; /* remove us from the list */
|
|
|
|
*pps1 = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} lws_end_foreach_llp(pps1, next);
|
|
|
|
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: %d\n", __func__, lws_wsi_tag(wsi), pps->type);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
switch (pps->type) {
|
|
|
|
|
|
|
|
case LWS_H2_PPS_MY_SETTINGS:
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* if any of our settings varies from h2 "default defaults"
|
2017-11-24 10:54:59 +08:00
|
|
|
* then we must inform the peer
|
2017-10-13 10:33:02 +08:00
|
|
|
*/
|
|
|
|
for (n = 1; n < H2SET_COUNT; n++)
|
2019-12-26 02:35:41 +00:00
|
|
|
if (h2n->our_set.s[n] != lws_h2_defaults.s[n]) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_debug("sending SETTING %d 0x%x\n", n,
|
2020-01-02 08:32:23 +00:00
|
|
|
(unsigned int)
|
|
|
|
wsi->h2.h2n->our_set.s[n]);
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_set_bin(wsi, n, &set[LWS_PRE + m]);
|
2020-12-12 06:21:40 +00:00
|
|
|
m += (int)sizeof(h2n->one_setting);
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,
|
2020-12-12 06:21:40 +00:00
|
|
|
flags, LWS_H2_STREAM_ID_MASTER, (unsigned int)m,
|
2017-10-13 10:33:02 +08:00
|
|
|
&set[LWS_PRE]);
|
|
|
|
if (n != m) {
|
|
|
|
lwsl_info("send %d %d\n", n, m);
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
case LWS_H2_PPS_SETTINGS_INITIAL_UPDATE_WINDOW:
|
|
|
|
q = &set[LWS_PRE];
|
2020-12-12 06:21:40 +00:00
|
|
|
*q++ = (uint8_t)(H2SET_INITIAL_WINDOW_SIZE >> 8);
|
|
|
|
*q++ = (uint8_t)(H2SET_INITIAL_WINDOW_SIZE);
|
|
|
|
*q++ = (uint8_t)(pps->u.update_window.credit >> 24);
|
|
|
|
*q++ = (uint8_t)(pps->u.update_window.credit >> 16);
|
|
|
|
*q++ = (uint8_t)(pps->u.update_window.credit >> 8);
|
|
|
|
*q = (uint8_t)(pps->u.update_window.credit);
|
2019-12-26 02:35:41 +00:00
|
|
|
|
|
|
|
lwsl_debug("%s: resetting initial window to %d\n", __func__,
|
|
|
|
(int)pps->u.update_window.credit);
|
|
|
|
|
|
|
|
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,
|
|
|
|
flags, LWS_H2_STREAM_ID_MASTER, 6,
|
|
|
|
&set[LWS_PRE]);
|
|
|
|
if (n != 6) {
|
|
|
|
lwsl_info("send %d %d\n", n, m);
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_PPS_ACK_SETTINGS:
|
|
|
|
/* send ack ... always empty */
|
|
|
|
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS, 1,
|
2018-11-23 08:47:56 +08:00
|
|
|
LWS_H2_STREAM_ID_MASTER, 0,
|
|
|
|
&set[LWS_PRE]);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (n) {
|
2020-12-20 08:34:23 +00:00
|
|
|
lwsl_err("%s: writing settings ack frame failed %d\n", __func__, n);
|
2017-10-13 10:33:02 +08:00
|
|
|
goto bail;
|
|
|
|
}
|
2019-12-26 02:35:41 +00:00
|
|
|
wsi->h2_acked_settings = 0;
|
2017-10-13 10:33:02 +08:00
|
|
|
/* this is the end of the preface dance then? */
|
2018-04-02 11:55:17 +08:00
|
|
|
if (lwsi_state(wsi) == LRS_H2_AWAIT_SETTINGS) {
|
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.fop_fd = NULL;
|
2019-08-18 10:35:43 +01:00
|
|
|
#endif
|
2017-10-13 10:33:02 +08:00
|
|
|
if (lws_is_ssl(lws_get_network_wsi(wsi)))
|
|
|
|
break;
|
2020-05-07 15:21:48 -07:00
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.vhost->options &
|
2020-05-07 15:21:48 -07:00
|
|
|
LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE)
|
|
|
|
break;
|
|
|
|
|
2015-12-14 08:52:03 +08:00
|
|
|
/*
|
2017-10-13 10:33:02 +08:00
|
|
|
* we need to treat the headers from the upgrade as the
|
|
|
|
* first job. So these need to get shifted to sid 1.
|
2014-10-08 12:00:53 +08:00
|
|
|
*/
|
2021-04-04 04:06:24 +01:00
|
|
|
|
|
|
|
lws_context_lock(wsi->a.context, "h2 mig");
|
|
|
|
lws_vhost_lock(wsi->a.vhost);
|
|
|
|
|
|
|
|
h2n->swsi = __lws_wsi_server_new(wsi->a.vhost, wsi, 1);
|
|
|
|
|
|
|
|
lws_vhost_unlock(wsi->a.vhost);
|
|
|
|
lws_context_unlock(wsi->a.context);
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!h2n->swsi)
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
/* pass on the initial headers to SID 1 */
|
2018-04-27 15:20:56 +08:00
|
|
|
h2n->swsi->http.ah = wsi->http.ah;
|
|
|
|
wsi->http.ah = NULL;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("%s: inherited headers %p\n", __func__,
|
2018-04-27 15:20:56 +08:00
|
|
|
h2n->swsi->http.ah);
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->swsi->txc.tx_cr = (int32_t)
|
2019-12-26 02:35:41 +00:00
|
|
|
h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE];
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("initial tx credit on %s: %d\n",
|
|
|
|
lws_wsi_tag(h2n->swsi),
|
|
|
|
(int)h2n->swsi->txc.tx_cr);
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->h2.initialized = 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
/* demanded by HTTP2 */
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->h2.END_STREAM = 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("servicing initial http request\n");
|
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_SERVER)
|
2017-10-13 10:33:02 +08:00
|
|
|
if (lws_http_action(h2n->swsi))
|
|
|
|
goto bail;
|
2019-08-18 10:35:43 +01:00
|
|
|
#endif
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2019-09-18 13:09:32 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* h2 only has PING... ACK = 0 = ping, ACK = 1 = pong
|
|
|
|
*/
|
|
|
|
|
|
|
|
case LWS_H2_PPS_PING:
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_PPS_PONG:
|
2019-09-18 13:09:32 +01:00
|
|
|
if (pps->type == LWS_H2_PPS_PING)
|
|
|
|
lwsl_info("sending PING\n");
|
|
|
|
else {
|
|
|
|
lwsl_info("sending PONG\n");
|
|
|
|
flags = LWS_H2_FLAG_SETTINGS_ACK;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
memcpy(&set[LWS_PRE], pps->u.ping.ping_payload, 8);
|
2019-09-18 13:09:32 +01:00
|
|
|
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING, flags,
|
2017-10-13 10:33:02 +08:00
|
|
|
LWS_H2_STREAM_ID_MASTER, 8,
|
|
|
|
&set[LWS_PRE]);
|
2019-09-18 13:09:32 +01:00
|
|
|
if (n != 8)
|
2017-10-13 10:33:02 +08:00
|
|
|
goto bail;
|
2019-09-18 13:09:32 +01:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
break;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_PPS_GOAWAY:
|
|
|
|
lwsl_info("LWS_H2_PPS_GOAWAY\n");
|
2020-12-12 06:21:40 +00:00
|
|
|
*p++ = (uint8_t)(pps->u.ga.highest_sid >> 24);
|
|
|
|
*p++ = (uint8_t)(pps->u.ga.highest_sid >> 16);
|
|
|
|
*p++ = (uint8_t)(pps->u.ga.highest_sid >> 8);
|
|
|
|
*p++ = (uint8_t)(pps->u.ga.highest_sid);
|
|
|
|
*p++ = (uint8_t)(pps->u.ga.err >> 24);
|
|
|
|
*p++ = (uint8_t)(pps->u.ga.err >> 16);
|
|
|
|
*p++ = (uint8_t)(pps->u.ga.err >> 8);
|
|
|
|
*p++ = (uint8_t)(pps->u.ga.err);
|
2017-10-16 12:52:32 +08:00
|
|
|
q = (unsigned char *)pps->u.ga.str;
|
2017-10-13 10:33:02 +08:00
|
|
|
n = 0;
|
2017-10-20 17:45:02 +08:00
|
|
|
while (*q && n++ < (int)sizeof(pps->u.ga.str))
|
2017-10-13 10:33:02 +08:00
|
|
|
*p++ = *q++;
|
|
|
|
h2n->we_told_goaway = 1;
|
|
|
|
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_GOAWAY, 0,
|
|
|
|
LWS_H2_STREAM_ID_MASTER,
|
2020-12-12 06:21:40 +00:00
|
|
|
(unsigned int)lws_ptr_diff(p, &set[LWS_PRE]),
|
2017-10-25 08:00:23 +08:00
|
|
|
&set[LWS_PRE]);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (n != 4) {
|
|
|
|
lwsl_info("send %d %d\n", n, m);
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
case LWS_H2_PPS_RST_STREAM:
|
|
|
|
lwsl_info("LWS_H2_PPS_RST_STREAM\n");
|
2020-12-12 06:21:40 +00:00
|
|
|
*p++ = (uint8_t)(pps->u.rs.err >> 24);
|
|
|
|
*p++ = (uint8_t)(pps->u.rs.err >> 16);
|
|
|
|
*p++ = (uint8_t)(pps->u.rs.err >> 8);
|
|
|
|
*p++ = (uint8_t)(pps->u.rs.err);
|
2017-10-13 10:33:02 +08:00
|
|
|
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_RST_STREAM,
|
|
|
|
0, pps->u.rs.sid, 4, &set[LWS_PRE]);
|
|
|
|
if (n != 4) {
|
|
|
|
lwsl_info("send %d %d\n", n, m);
|
|
|
|
goto bail;
|
|
|
|
}
|
2019-12-23 11:31:57 +00:00
|
|
|
cwsi = lws_wsi_mux_from_id(wsi, pps->u.rs.sid);
|
2018-04-17 11:43:20 +08:00
|
|
|
if (cwsi) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s: closing cwsi %s %s %s (wsi %s)\n",
|
|
|
|
__func__, lws_wsi_tag(cwsi),
|
|
|
|
cwsi->role_ops->name,
|
|
|
|
cwsi->a.protocol->name, lws_wsi_tag(wsi));
|
2018-02-03 13:48:18 +08:00
|
|
|
lws_close_free_wsi(cwsi, 0, "reset stream");
|
2018-04-17 11:43:20 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_PPS_UPDATE_WINDOW:
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_info("Issuing LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n",
|
2019-11-05 21:00:45 +00:00
|
|
|
(int)pps->u.update_window.sid,
|
|
|
|
(int)pps->u.update_window.credit);
|
2020-12-12 06:21:40 +00:00
|
|
|
*p++ = (uint8_t)((pps->u.update_window.credit >> 24) & 0x7f); /* 31b */
|
|
|
|
*p++ = (uint8_t)(pps->u.update_window.credit >> 16);
|
|
|
|
*p++ = (uint8_t)(pps->u.update_window.credit >> 8);
|
|
|
|
*p++ = (uint8_t)(pps->u.update_window.credit);
|
2017-10-13 10:33:02 +08:00
|
|
|
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_WINDOW_UPDATE,
|
2017-10-16 12:52:32 +08:00
|
|
|
0, pps->u.update_window.sid, 4,
|
|
|
|
&set[LWS_PRE]);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (n != 4) {
|
|
|
|
lwsl_info("send %d %d\n", n, m);
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
lws_free(pps);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bail:
|
|
|
|
lws_free(pps);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-10-16 15:08:25 +01:00
|
|
|
static int
|
|
|
|
lws_h2_parse_end_of_frame(struct lws *wsi);
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* The frame header part has just completely arrived.
|
2017-11-24 10:54:59 +08:00
|
|
|
* Perform actions for header completion.
|
2017-10-13 10:33:02 +08:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
lws_h2_parse_frame_header(struct lws *wsi)
|
|
|
|
{
|
2017-12-01 11:09:32 +08:00
|
|
|
struct lws_h2_netconn *h2n = wsi->h2.h2n;
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws_h2_protocol_send *pps;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We just got the frame header
|
|
|
|
*/
|
|
|
|
h2n->count = 0;
|
|
|
|
h2n->swsi = wsi;
|
|
|
|
/* b31 is a reserved bit */
|
|
|
|
h2n->sid = h2n->sid & 0x7fffffff;
|
|
|
|
|
|
|
|
if (h2n->sid && !(h2n->sid & 1)) {
|
2020-12-20 08:34:23 +00:00
|
|
|
char pes[32];
|
|
|
|
lws_snprintf(pes, sizeof(pes), "Even Stream ID 0x%x", (unsigned int)h2n->sid);
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, pes);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* let the network wsi live a bit longer if subs are active */
|
2019-06-05 05:04:17 +01:00
|
|
|
|
2019-01-30 20:59:56 +08:00
|
|
|
if (!wsi->immortal_substream_count)
|
2019-09-13 10:33:24 +01:00
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->keepalive_timeout ?
|
|
|
|
wsi->a.vhost->keepalive_timeout : 31);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (h2n->sid)
|
2019-12-23 11:31:57 +00:00
|
|
|
h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_debug("%s (%s): fr hdr: typ 0x%x, fla 0x%x, sid 0x%x, len 0x%x\n",
|
|
|
|
lws_wsi_tag(wsi), lws_wsi_tag(h2n->swsi), h2n->type,
|
|
|
|
h2n->flags, (unsigned int)h2n->sid, (unsigned int)h2n->length);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (h2n->we_told_goaway && h2n->sid > h2n->highest_sid)
|
|
|
|
h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
|
|
|
|
|
2020-12-01 13:11:28 +00:00
|
|
|
if (h2n->type >= LWS_H2_FRAME_TYPE_COUNT) {
|
|
|
|
lwsl_info("%s: ignoring unknown frame type %d (len %d)\n", __func__, h2n->type, (unsigned int)h2n->length);
|
|
|
|
/* we MUST ignore frames we don't understand */
|
|
|
|
h2n->type = LWS_H2_FRAME_TYPE_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Even if we have decided to logically ignore this frame, we must
|
|
|
|
* consume the correct "frame length" amount of data to retain sync
|
|
|
|
*/
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
if (h2n->length > h2n->our_set.s[H2SET_MAX_FRAME_SIZE]) {
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* peer sent us something bigger than we told
|
|
|
|
* it we would allow
|
|
|
|
*/
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_info("%s: received oversize frame %d\n", __func__,
|
|
|
|
(unsigned int)h2n->length);
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
|
|
|
|
"Peer ignored our frame size setting");
|
2018-04-02 11:55:17 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (h2n->swsi)
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s, State: %s, received cmd %d\n",
|
|
|
|
__func__, lws_wsi_tag(h2n->swsi),
|
2017-12-01 11:09:32 +08:00
|
|
|
h2_state_names[h2n->swsi->h2.h2_state], h2n->type);
|
2017-10-13 10:33:02 +08:00
|
|
|
else {
|
|
|
|
/* if it's data, either way no swsi means CLOSED state */
|
|
|
|
if (h2n->type == LWS_H2_FRAME_TYPE_DATA) {
|
2018-11-12 15:24:42 +08:00
|
|
|
if (h2n->sid <= h2n->highest_sid_opened
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2018-11-12 15:24:42 +08:00
|
|
|
&& wsi->client_h2_alpn
|
|
|
|
#endif
|
|
|
|
) {
|
2019-10-16 15:08:25 +01:00
|
|
|
lwsl_notice("ignoring straggling data fl 0x%x\n",
|
|
|
|
h2n->flags);
|
2018-11-23 08:47:56 +08:00
|
|
|
/* ie, IGNORE */
|
|
|
|
h2n->type = LWS_H2_FRAME_TYPE_COUNT;
|
2018-03-11 11:26:06 +08:00
|
|
|
} else {
|
2020-12-19 09:13:24 +00:00
|
|
|
lwsl_info("%s: received %d bytes data for unknown sid %d, highest known %d\n",
|
|
|
|
__func__, (int)h2n->length, (int)h2n->sid, (int)h2n->highest_sid_opened);
|
|
|
|
|
|
|
|
// if (h2n->sid > h2n->highest_sid_opened) {
|
2018-03-11 11:26:06 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
|
2017-11-28 07:46:22 +08:00
|
|
|
"Data for nonexistent sid");
|
2018-03-11 11:26:06 +08:00
|
|
|
return 0;
|
2020-12-19 09:13:24 +00:00
|
|
|
// }
|
2018-03-11 11:26:06 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
/* if the sid is credible, treat as wsi for it closed */
|
|
|
|
if (h2n->sid > h2n->highest_sid_opened &&
|
|
|
|
h2n->type != LWS_H2_FRAME_TYPE_HEADERS &&
|
|
|
|
h2n->type != LWS_H2_FRAME_TYPE_PRIORITY) {
|
|
|
|
/* if not credible, reject it */
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s, No child for sid %d, rxcmd %d\n",
|
|
|
|
__func__, lws_wsi_tag(h2n->swsi), (unsigned int)h2n->sid, h2n->type);
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
|
2017-11-28 07:46:22 +08:00
|
|
|
"Data for nonexistent sid");
|
2017-10-13 10:33:02 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-24 17:02:36 +00:00
|
|
|
if (h2n->swsi && h2n->sid && h2n->type != LWS_H2_FRAME_TYPE_COUNT &&
|
2017-12-01 11:09:32 +08:00
|
|
|
!(http2_rx_validity[h2n->swsi->h2.h2_state] & (1 << h2n->type))) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\n",
|
|
|
|
__func__, lws_wsi_tag(h2n->swsi),
|
2017-12-01 11:09:32 +08:00
|
|
|
h2_state_names[h2n->swsi->h2.h2_state], h2n->type,
|
|
|
|
http2_rx_validity[h2n->swsi->h2.h2_state]);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED ||
|
|
|
|
h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE)
|
2017-10-13 10:33:02 +08:00
|
|
|
n = H2_ERR_STREAM_CLOSED;
|
|
|
|
else
|
|
|
|
n = H2_ERR_PROTOCOL_ERROR;
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_h2_goaway(wsi, (unsigned int)n, "invalid rx for state");
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-01 13:11:28 +00:00
|
|
|
if (h2n->cont_exp && h2n->type != LWS_H2_FRAME_TYPE_COUNT &&
|
|
|
|
(h2n->cont_exp_sid != h2n->sid ||
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->type != LWS_H2_FRAME_TYPE_CONTINUATION)) {
|
2019-11-05 21:00:45 +00:00
|
|
|
lwsl_info("%s: expected cont on sid %u (got %d on sid %u)\n",
|
|
|
|
__func__, (unsigned int)h2n->cont_exp_sid, h2n->type,
|
|
|
|
(unsigned int)h2n->sid);
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->cont_exp = 0;
|
|
|
|
if (h2n->cont_exp_headers)
|
|
|
|
n = H2_ERR_COMPRESSION_ERROR;
|
|
|
|
else
|
|
|
|
n = H2_ERR_PROTOCOL_ERROR;
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_h2_goaway(wsi, (unsigned int)n, "Continuation hdrs State");
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (h2n->type) {
|
|
|
|
case LWS_H2_FRAME_TYPE_DATA:
|
|
|
|
lwsl_info("seen incoming LWS_H2_FRAME_TYPE_DATA start\n");
|
|
|
|
if (!h2n->sid) {
|
2018-04-26 15:27:02 +08:00
|
|
|
lwsl_info("DATA: 0 sid\n");
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "DATA 0 sid");
|
|
|
|
break;
|
|
|
|
}
|
2019-11-05 21:00:45 +00:00
|
|
|
lwsl_info("Frame header DATA: sid %u, flags 0x%x, len %u\n",
|
|
|
|
(unsigned int)h2n->sid, h2n->flags,
|
|
|
|
(unsigned int)h2n->length);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-06 09:58:48 +08:00
|
|
|
if (!h2n->swsi) {
|
|
|
|
lwsl_notice("DATA: NULL swsi\n");
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-04-26 15:27:02 +08:00
|
|
|
lwsl_info("DATA rx on state %d\n", h2n->swsi->h2.h2_state);
|
|
|
|
|
2017-10-16 12:52:32 +08:00
|
|
|
if (
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE ||
|
|
|
|
h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, "conn closed");
|
|
|
|
break;
|
|
|
|
}
|
2019-10-16 15:08:25 +01:00
|
|
|
|
|
|
|
if (h2n->length == 0)
|
|
|
|
lws_h2_parse_end_of_frame(wsi);
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
2019-10-16 15:08:25 +01:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_PRIORITY:
|
|
|
|
lwsl_info("LWS_H2_FRAME_TYPE_PRIORITY complete frame\n");
|
|
|
|
if (!h2n->sid) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Priority has 0 sid");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (h2n->length != 5) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
|
|
|
|
"Priority has length other than 5");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LWS_H2_FRAME_TYPE_PUSH_PROMISE:
|
|
|
|
lwsl_info("LWS_H2_FRAME_TYPE_PUSH_PROMISE complete frame\n");
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "Server only");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_GOAWAY:
|
2018-03-11 11:26:06 +08:00
|
|
|
lwsl_debug("LWS_H2_FRAME_TYPE_GOAWAY received\n");
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_RST_STREAM:
|
|
|
|
if (!h2n->sid)
|
|
|
|
return 1;
|
|
|
|
if (!h2n->swsi) {
|
|
|
|
if (h2n->sid <= h2n->highest_sid_opened)
|
2014-10-27 16:46:44 +08:00
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"crazy sid on RST_STREAM");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (h2n->length != 4) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
|
|
|
|
"RST_STREAM can only be length 4");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_SETTINGS:
|
|
|
|
lwsl_info("LWS_H2_FRAME_TYPE_SETTINGS complete frame\n");
|
|
|
|
/* nonzero sid on settings is illegal */
|
|
|
|
if (h2n->sid) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Settings has nonzero sid");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) {
|
2020-08-26 11:06:31 +01:00
|
|
|
if (h2n->length % 6) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
|
|
|
|
"Settings length error");
|
2014-10-27 16:46:44 +08:00
|
|
|
break;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (h2n->type == LWS_H2_FRAME_TYPE_COUNT)
|
|
|
|
return 0;
|
2018-04-26 15:27:02 +08:00
|
|
|
|
2019-10-02 08:55:12 -07:00
|
|
|
if (wsi->upgraded_to_http2 &&
|
|
|
|
#if defined(LWS_WITH_CLIENT)
|
|
|
|
(!(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) ||
|
|
|
|
#else
|
|
|
|
(
|
|
|
|
#endif
|
|
|
|
!wsi->h2_acked_settings)) {
|
|
|
|
|
2018-04-26 15:27:02 +08:00
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
2019-10-02 08:55:12 -07:00
|
|
|
wsi->h2_acked_settings = 1;
|
2018-04-26 15:27:02 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* came to us with ACK set... not allowed to have payload */
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (h2n->length) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
|
|
|
|
"Settings with ACK not allowed payload");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LWS_H2_FRAME_TYPE_PING:
|
|
|
|
if (h2n->sid) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Ping has nonzero sid");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (h2n->length != 8) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
|
|
|
|
"Ping payload can only be 8");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LWS_H2_FRAME_TYPE_CONTINUATION:
|
2019-11-12 10:17:36 +00:00
|
|
|
lwsl_info("LWS_H2_FRAME_TYPE_CONTINUATION: sid = %u %d %d\n",
|
|
|
|
(unsigned int)h2n->sid, (int)h2n->cont_exp,
|
|
|
|
(int)h2n->cont_exp_sid);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (!h2n->cont_exp ||
|
|
|
|
h2n->cont_exp_sid != h2n->sid ||
|
|
|
|
!h2n->sid ||
|
|
|
|
!h2n->swsi) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"unexpected CONTINUATION");
|
|
|
|
break;
|
|
|
|
}
|
2019-11-12 10:17:36 +00:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (h2n->swsi->h2.END_HEADERS) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"END_HEADERS already seen");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* END_STREAM is in HEADERS, skip resetting it */
|
|
|
|
goto update_end_headers;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_HEADERS:
|
2019-11-05 21:00:45 +00:00
|
|
|
lwsl_info("HEADERS: frame header: sid = %u\n",
|
|
|
|
(unsigned int)h2n->sid);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!h2n->sid) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "sid 0");
|
|
|
|
return 1;
|
|
|
|
}
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
if (h2n->swsi && !h2n->swsi->h2.END_STREAM &&
|
|
|
|
h2n->swsi->h2.END_HEADERS &&
|
|
|
|
!(h2n->flags & LWS_H2_FLAG_END_STREAM)) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"extra HEADERS together");
|
2018-04-26 15:27:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2018-03-27 09:17:19 +08:00
|
|
|
if (wsi->client_h2_alpn) {
|
|
|
|
if (h2n->sid) {
|
2019-12-23 11:31:57 +00:00
|
|
|
h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid);
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("HEADERS: nwsi %s: sid %u mapped "
|
|
|
|
"to wsi %s\n", lws_wsi_tag(wsi),
|
|
|
|
(unsigned int)h2n->sid,
|
|
|
|
lws_wsi_tag(h2n->swsi));
|
2018-04-03 12:00:46 +08:00
|
|
|
if (!h2n->swsi)
|
|
|
|
break;
|
2018-03-27 09:17:19 +08:00
|
|
|
}
|
|
|
|
goto update_end_headers;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!h2n->swsi) {
|
|
|
|
/* no more children allowed by parent */
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->mux.child_count + 1 >
|
2019-12-26 02:35:41 +00:00
|
|
|
wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Another stream not allowed");
|
|
|
|
|
|
|
|
return 1;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
/*
|
|
|
|
* The peer has sent us a HEADERS implying the creation
|
|
|
|
* of a new stream
|
|
|
|
*/
|
|
|
|
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_context_lock(wsi->a.context, "h2 new str");
|
|
|
|
lws_vhost_lock(wsi->a.vhost);
|
|
|
|
|
|
|
|
h2n->swsi = __lws_wsi_server_new(wsi->a.vhost, wsi,
|
|
|
|
h2n->sid);
|
|
|
|
|
|
|
|
lws_vhost_unlock(wsi->a.vhost);
|
|
|
|
lws_context_unlock(wsi->a.context);
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!h2n->swsi) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"OOM");
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
return 1;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
2018-02-05 10:54:18 +08:00
|
|
|
|
2020-04-06 13:22:01 +01:00
|
|
|
if (h2n->sid >= h2n->highest_sid)
|
|
|
|
h2n->highest_sid = h2n->sid + 2;
|
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
h2n->swsi->h2.initialized = 1;
|
2018-02-05 10:54:18 +08:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
if (lws_h2_update_peer_txcredit(h2n->swsi,
|
|
|
|
h2n->swsi->mux.my_sid, 4 * 65536))
|
vhost_destroy: use vhost wsi reference counting to trigger destroy
This changes the vhost destroy flow to only hand off the listen
socket if another vhost sharing it, and mark the vhost as
being_destroyed.
Each tsi calls lws_check_deferred_free() once a second, if it sees
any vhost being_destroyed there, it closes all wsi on its tsi on
the same vhost, one time.
As the wsi on the vhost complete close (ie, after libuv async close
if on libuv event loop), they decrement a reference count for all
wsi open on the vhost. The tsi who closes the last one then
completes the destroy flow for the vhost itself... it's random
which tsi completes the vhost destroy but since there are no
wsi left on the vhost, and it holds the context lock, nothing
can conflict.
The advantage of this is that owning tsi do the close for wsi
that are bound to the vhost under destruction, at a time when
they are guaranteed to be idle for service, and they do it with
both vhost and context locks owned, so no other service thread
can conflict for stuff protected by those either.
For the situation the user code may have allocations attached to
the vhost, this adds args to lws_vhost_destroy() to allow destroying
the user allocations just before the vhost is freed.
2018-06-16 09:31:07 +08:00
|
|
|
goto cleanup_wsi;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ah needs attaching to child wsi, even though
|
|
|
|
* we only fill it from network wsi
|
|
|
|
*/
|
2018-04-27 15:20:56 +08:00
|
|
|
if (!h2n->swsi->http.ah)
|
2017-10-13 10:33:02 +08:00
|
|
|
if (lws_header_table_attach(h2n->swsi, 0)) {
|
|
|
|
lwsl_err("%s: Failed to get ah\n", __func__);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The first use of a new stream identifier implicitly closes
|
|
|
|
* all streams in the "idle" state that might have been
|
|
|
|
* initiated by that peer with a lower-valued stream identifier.
|
|
|
|
*
|
|
|
|
* For example, if a client sends a HEADERS frame on stream 7
|
|
|
|
* without ever sending a frame on stream 5, then stream 5
|
|
|
|
* transitions to the "closed" state when the first frame for
|
|
|
|
* stream 7 is sent or received.
|
|
|
|
*/
|
2019-12-23 11:31:57 +00:00
|
|
|
lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) {
|
|
|
|
if (w->mux.my_sid < h2n->sid &&
|
2017-12-01 11:09:32 +08:00
|
|
|
w->h2.h2_state == LWS_H2_STATE_IDLE)
|
2018-02-03 13:48:18 +08:00
|
|
|
lws_close_free_wsi(w, 0, "h2 sid close");
|
2019-12-23 11:31:57 +00:00
|
|
|
assert(w->mux.sibling_list != w);
|
|
|
|
} lws_end_foreach_ll(w, mux.sibling_list);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2021-01-15 19:53:55 +00:00
|
|
|
h2n->cont_exp = !(h2n->flags & LWS_H2_FLAG_END_HEADERS);
|
|
|
|
h2n->cont_exp_sid = h2n->sid;
|
|
|
|
h2n->cont_exp_headers = 1;
|
|
|
|
// lws_header_table_reset(h2n->swsi, 0);
|
|
|
|
|
|
|
|
update_end_headers:
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (lws_check_opt(h2n->swsi->a.vhost->options,
|
2019-09-13 10:33:24 +01:00
|
|
|
LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't directly timeout streams that enter the
|
|
|
|
* half-closed remote state, allowing immortal long
|
|
|
|
* poll
|
|
|
|
*/
|
2019-12-23 11:31:57 +00:00
|
|
|
lws_mux_mark_immortal(h2n->swsi);
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: h2 stream entering long poll\n",
|
|
|
|
__func__, lws_wsi_tag(h2n->swsi));
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2019-09-13 10:33:24 +01:00
|
|
|
} else {
|
|
|
|
h2n->swsi->h2.END_STREAM =
|
2017-10-16 12:52:32 +08:00
|
|
|
!!(h2n->flags & LWS_H2_FLAG_END_STREAM);
|
2019-09-13 10:33:24 +01:00
|
|
|
lwsl_debug("%s: hdr END_STREAM = %d\n",__func__,
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->h2.END_STREAM);
|
2019-09-13 10:33:24 +01:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
/* no END_HEADERS means CONTINUATION must come */
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->h2.END_HEADERS =
|
2017-10-13 10:33:02 +08:00
|
|
|
!!(h2n->flags & LWS_H2_FLAG_END_HEADERS);
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: END_HEADERS %d\n", __func__, lws_wsi_tag(h2n->swsi),
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->swsi->h2.END_HEADERS);
|
2017-12-01 11:09:32 +08:00
|
|
|
if (h2n->swsi->h2.END_HEADERS)
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->cont_exp = 0;
|
2017-12-01 11:09:32 +08:00
|
|
|
lwsl_debug("END_HEADERS %d\n", h2n->swsi->h2.END_HEADERS);
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
vhost_destroy: use vhost wsi reference counting to trigger destroy
This changes the vhost destroy flow to only hand off the listen
socket if another vhost sharing it, and mark the vhost as
being_destroyed.
Each tsi calls lws_check_deferred_free() once a second, if it sees
any vhost being_destroyed there, it closes all wsi on its tsi on
the same vhost, one time.
As the wsi on the vhost complete close (ie, after libuv async close
if on libuv event loop), they decrement a reference count for all
wsi open on the vhost. The tsi who closes the last one then
completes the destroy flow for the vhost itself... it's random
which tsi completes the vhost destroy but since there are no
wsi left on the vhost, and it holds the context lock, nothing
can conflict.
The advantage of this is that owning tsi do the close for wsi
that are bound to the vhost under destruction, at a time when
they are guaranteed to be idle for service, and they do it with
both vhost and context locks owned, so no other service thread
can conflict for stuff protected by those either.
For the situation the user code may have allocations attached to
the vhost, this adds args to lws_vhost_destroy() to allow destroying
the user allocations just before the vhost is freed.
2018-06-16 09:31:07 +08:00
|
|
|
cleanup_wsi:
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_WINDOW_UPDATE:
|
|
|
|
if (h2n->length != 4) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
|
|
|
|
"window update frame not 4");
|
2014-10-08 12:00:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("LWS_H2_FRAME_TYPE_WINDOW_UPDATE\n");
|
|
|
|
break;
|
2018-03-11 11:26:06 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_COUNT:
|
2020-12-01 13:11:28 +00:00
|
|
|
if (h2n->length == 0)
|
|
|
|
lws_h2_parse_end_of_frame(wsi);
|
|
|
|
else
|
|
|
|
lwsl_debug("%s: going on to deal with unknown frame remaining len %d\n", __func__, (unsigned int)h2n->length);
|
2018-03-11 11:26:06 +08:00
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
default:
|
|
|
|
lwsl_info("%s: ILLEGAL FRAME TYPE %d\n", __func__, h2n->type);
|
|
|
|
h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (h2n->length == 0)
|
|
|
|
h2n->frame_state = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-29 00:31:41 +01:00
|
|
|
static const char * const method_names[] = {
|
2020-02-28 10:31:04 +00:00
|
|
|
"GET", "POST",
|
|
|
|
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
|
|
|
|
"OPTIONS", "PUT", "PATCH", "DELETE",
|
|
|
|
#endif
|
|
|
|
"CONNECT", "HEAD"
|
2019-07-29 00:31:41 +01:00
|
|
|
};
|
|
|
|
static unsigned char method_index[] = {
|
|
|
|
WSI_TOKEN_GET_URI,
|
|
|
|
WSI_TOKEN_POST_URI,
|
2020-02-28 10:31:04 +00:00
|
|
|
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
|
2019-07-29 00:31:41 +01: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
|
2019-07-29 00:31:41 +01:00
|
|
|
WSI_TOKEN_CONNECT,
|
|
|
|
WSI_TOKEN_HEAD_URI,
|
|
|
|
};
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* The last byte of the whole frame has been handled.
|
|
|
|
* Perform actions for frame completion.
|
2017-12-07 07:20:47 +08:00
|
|
|
*
|
|
|
|
* This is the crunch time for parsing that may have occured on a network
|
|
|
|
* wsi with a pending partial send... we may call lws_http_action() to send
|
|
|
|
* a response, conflicting with the partial.
|
|
|
|
*
|
|
|
|
* So in that case we change the wsi state and do the lws_http_action() in the
|
|
|
|
* WRITABLE handler as a priority.
|
2017-10-13 10:33:02 +08:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
lws_h2_parse_end_of_frame(struct lws *wsi)
|
|
|
|
{
|
2017-12-01 11:09:32 +08:00
|
|
|
struct lws_h2_netconn *h2n = wsi->h2.h2n;
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws *eff_wsi = wsi;
|
|
|
|
const char *p;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
h2n->frame_state = 0;
|
|
|
|
h2n->count = 0;
|
|
|
|
|
|
|
|
if (h2n->sid)
|
2019-12-23 11:31:57 +00:00
|
|
|
h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (h2n->sid > h2n->highest_sid)
|
|
|
|
h2n->highest_sid = h2n->sid;
|
|
|
|
|
2018-11-03 14:47:48 +08:00
|
|
|
if (h2n->collected_priority && (h2n->dep & ~(1u << 31)) == h2n->sid) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "depends on own sid");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (h2n->type) {
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_SETTINGS:
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->client_h2_alpn && !wsi->client_mux_migrated &&
|
2018-03-27 09:17:19 +08:00
|
|
|
!(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) {
|
2018-10-10 13:54:43 +08:00
|
|
|
struct lws_h2_protocol_send *pps;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
/* migrate original client ask on to substream 1 */
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2018-03-27 09:17:19 +08:00
|
|
|
wsi->http.fop_fd = NULL;
|
2019-08-18 10:35:43 +01:00
|
|
|
#endif
|
2019-10-10 16:37:38 +01:00
|
|
|
lwsl_info("%s: migrating\n", __func__);
|
2019-12-23 11:31:57 +00:00
|
|
|
wsi->client_mux_migrated = 1;
|
2018-03-27 09:17:19 +08:00
|
|
|
/*
|
|
|
|
* we need to treat the headers from the upgrade as the
|
|
|
|
* first job. So these need to get shifted to sid 1.
|
|
|
|
*/
|
2021-04-04 04:06:24 +01:00
|
|
|
lws_context_lock(wsi->a.context, "h2 mig");
|
|
|
|
lws_vhost_lock(wsi->a.vhost);
|
|
|
|
|
|
|
|
h2n->swsi = __lws_wsi_server_new(wsi->a.vhost, wsi, 1);
|
|
|
|
|
|
|
|
lws_vhost_unlock(wsi->a.vhost);
|
|
|
|
lws_context_unlock(wsi->a.context);
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
if (!h2n->swsi)
|
|
|
|
return 1;
|
|
|
|
h2n->sid = 1;
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
assert(lws_wsi_mux_from_id(wsi, 1) == h2n->swsi);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2020-12-20 08:34:23 +00:00
|
|
|
// lws_role_transition(wsi, LWSIFR_CLIENT,
|
|
|
|
// LRS_H2_WAITING_TO_SEND_HEADERS,
|
|
|
|
// &role_ops_h2);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
lws_role_transition(h2n->swsi, LWSIFR_CLIENT,
|
|
|
|
LRS_H2_WAITING_TO_SEND_HEADERS,
|
|
|
|
&role_ops_h2);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
/* pass on the initial headers to SID 1 */
|
2018-04-27 15:20:56 +08:00
|
|
|
h2n->swsi->http.ah = wsi->http.ah;
|
2021-03-16 13:32:05 +00:00
|
|
|
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
|
|
|
lws_fi_import(&h2n->swsi->fic, &wsi->fic);
|
|
|
|
#endif
|
2019-12-23 11:31:57 +00:00
|
|
|
h2n->swsi->client_mux_substream = 1;
|
2020-05-05 12:17:27 +01:00
|
|
|
h2n->swsi->client_h2_alpn = 1;
|
2019-10-02 10:49:18 -07:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
|
|
|
h2n->swsi->flags = wsi->flags;
|
2021-03-15 05:20:15 +00:00
|
|
|
#if defined(LWS_WITH_CONMON)
|
|
|
|
/* sid1 needs to represent the connection experience
|
|
|
|
* ... we take over responsibility for the DNS list
|
|
|
|
* copy as well
|
|
|
|
*/
|
|
|
|
h2n->swsi->conmon = wsi->conmon;
|
|
|
|
h2n->swsi->conmon_datum = wsi->conmon_datum;
|
|
|
|
h2n->swsi->sa46_peer = wsi->sa46_peer;
|
|
|
|
wsi->conmon.dns_results_copy = NULL;
|
2019-10-02 10:49:18 -07:00
|
|
|
#endif
|
2021-03-15 05:20:15 +00:00
|
|
|
#endif /* CLIENT */
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2021-05-07 10:01:59 +01:00
|
|
|
#if defined(LWS_WITH_SECURE_STREAMS)
|
|
|
|
if (wsi->for_ss) {
|
|
|
|
lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
|
|
|
|
|
|
|
|
h2n->swsi->for_ss = 1;
|
|
|
|
wsi->for_ss = 0;
|
|
|
|
|
|
|
|
if (h->wsi == wsi)
|
|
|
|
h->wsi = h2n->swsi;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
h2n->swsi->a.protocol = wsi->a.protocol;
|
2019-12-26 02:35:41 +00:00
|
|
|
if (h2n->swsi->user_space &&
|
|
|
|
!h2n->swsi->user_space_externally_allocated)
|
2019-08-08 21:15:57 +01:00
|
|
|
lws_free(h2n->swsi->user_space);
|
2018-03-27 09:17:19 +08:00
|
|
|
h2n->swsi->user_space = wsi->user_space;
|
|
|
|
h2n->swsi->user_space_externally_allocated =
|
|
|
|
wsi->user_space_externally_allocated;
|
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
|
|
|
h2n->swsi->a.opaque_user_data = wsi->a.opaque_user_data;
|
|
|
|
wsi->a.opaque_user_data = NULL;
|
2019-12-26 02:35:41 +00:00
|
|
|
h2n->swsi->txc.manual_initial_tx_credit =
|
|
|
|
wsi->txc.manual_initial_tx_credit;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
#if defined(LWS_WITH_TLS)
|
|
|
|
lws_strncpy(h2n->swsi->alpn, wsi->alpn,
|
|
|
|
sizeof(wsi->alpn));
|
|
|
|
#endif
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
wsi->user_space = NULL;
|
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
if (h2n->swsi->http.ah)
|
|
|
|
h2n->swsi->http.ah->wsi = h2n->swsi;
|
|
|
|
wsi->http.ah = NULL;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: MIGRATING nwsi %s -> swsi %s\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), lws_wsi_tag(h2n->swsi));
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->swsi->txc.tx_cr = (int32_t)
|
2019-12-26 02:35:41 +00:00
|
|
|
h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: initial tx credit on %s: %d\n",
|
|
|
|
__func__, lws_wsi_tag(h2n->swsi),
|
|
|
|
(int)h2n->swsi->txc.tx_cr);
|
2018-03-27 09:17:19 +08:00
|
|
|
h2n->swsi->h2.initialized = 1;
|
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
/* set our initial window size */
|
|
|
|
if (!wsi->h2.initialized) {
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->txc.tx_cr = (int32_t)
|
2019-12-26 02:35:41 +00:00
|
|
|
h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
|
2020-01-02 08:32:23 +00:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
lwsl_info("%s: initial tx credit for us to "
|
2020-12-25 05:54:19 +00:00
|
|
|
"write on nwsi %s: %d\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), (int)wsi->txc.tx_cr);
|
2019-12-26 02:35:41 +00:00
|
|
|
wsi->h2.initialized = 1;
|
|
|
|
}
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
lws_callback_on_writable(h2n->swsi);
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->h2_acked_settings ||
|
|
|
|
!(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM)
|
2019-10-02 08:55:12 -07:00
|
|
|
) {
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
2019-12-23 11:31:57 +00:00
|
|
|
lwsl_info("%s: SETTINGS ack PPS\n", __func__);
|
2019-10-02 08:55:12 -07:00
|
|
|
wsi->h2_acked_settings = 1;
|
|
|
|
}
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
/* also attach any queued guys */
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
lws_wsi_mux_apply_queue(wsi);
|
2018-03-27 09:17:19 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_CONTINUATION:
|
|
|
|
case LWS_H2_FRAME_TYPE_HEADERS:
|
|
|
|
|
2018-04-03 12:00:46 +08:00
|
|
|
if (!h2n->swsi)
|
|
|
|
break;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/* service the http request itself */
|
|
|
|
|
|
|
|
if (h2n->last_action_dyntable_resize) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"dyntable resize last in headers");
|
2014-10-08 12:00:53 +08:00
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!h2n->swsi->h2.END_HEADERS) {
|
2017-10-13 10:33:02 +08:00
|
|
|
/* we are not finished yet */
|
|
|
|
lwsl_info("witholding http action for continuation\n");
|
2019-11-12 10:17:36 +00:00
|
|
|
h2n->cont_exp_sid = h2n->sid;
|
|
|
|
h2n->cont_exp = 1;
|
2014-10-08 12:00:53 +08:00
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* confirm the hpack stream state is reasonable for finishing */
|
|
|
|
|
|
|
|
if (h2n->hpack != HPKS_TYPE) {
|
|
|
|
/* hpack incomplete */
|
2019-11-05 21:00:45 +00:00
|
|
|
lwsl_info("hpack incomplete %d (type %d, len %u)\n",
|
|
|
|
h2n->hpack, h2n->type,
|
|
|
|
(unsigned int)h2n->hpack_len);
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"hpack incomplete");
|
2014-10-08 12:00:53 +08:00
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* this is the last part of HEADERS */
|
2017-12-01 11:09:32 +08:00
|
|
|
switch (h2n->swsi->h2.h2_state) {
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_STATE_IDLE:
|
|
|
|
lws_h2_state(h2n->swsi, LWS_H2_STATE_OPEN);
|
2014-10-08 12:00:53 +08:00
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_STATE_RESERVED_REMOTE:
|
|
|
|
lws_h2_state(h2n->swsi, LWS_H2_STATE_HALF_CLOSED_LOCAL);
|
2014-10-08 12:00:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("http req, %s, h2n->swsi=%s\n", lws_wsi_tag(wsi),
|
|
|
|
lws_wsi_tag(h2n->swsi));
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->swsi->hdr_parsing_completed = 1;
|
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2020-01-02 08:32:23 +00:00
|
|
|
if (h2n->swsi->client_mux_substream &&
|
|
|
|
lws_client_interpret_server_handshake(h2n->swsi)) {
|
2021-06-17 10:07:04 +01:00
|
|
|
/*
|
|
|
|
* This is more complicated than it looks, one exit from
|
|
|
|
* interpret_server_handshake() is to do a close that
|
|
|
|
* turns into a redirect.
|
|
|
|
*
|
|
|
|
* In that case, the wsi survives having being reset
|
|
|
|
* and detached from any h2 identity. We need to get
|
|
|
|
* our parents out from touching it any more
|
|
|
|
*/
|
|
|
|
lwsl_info("%s: cli int serv hs closed, or redir\n", __func__);
|
|
|
|
return 2;
|
2018-03-27 09:17:19 +08:00
|
|
|
}
|
2018-11-12 15:24:42 +08:00
|
|
|
#endif
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (lws_hdr_extant(h2n->swsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
|
2020-08-18 12:57:58 +01:00
|
|
|
const char *simp = lws_hdr_simple_ptr(h2n->swsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_LENGTH);
|
|
|
|
|
|
|
|
if (!simp) /* coverity */
|
|
|
|
return 1;
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->swsi->http.rx_content_length = (unsigned long long)atoll(simp);
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->http.rx_content_remain =
|
|
|
|
h2n->swsi->http.rx_content_length;
|
2021-01-18 14:20:37 +00:00
|
|
|
h2n->swsi->http.content_length_given = 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("setting rx_content_length %lld\n",
|
2018-11-23 08:47:56 +08:00
|
|
|
(long long)h2n->swsi->http.rx_content_length);
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
{
|
|
|
|
int n = 0, len;
|
|
|
|
char buf[256];
|
|
|
|
const unsigned char *c;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
do {
|
2020-12-12 06:21:40 +00:00
|
|
|
c = lws_token_to_string((enum lws_token_indexes)n);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!c) {
|
|
|
|
n++;
|
|
|
|
continue;
|
|
|
|
}
|
2014-10-17 08:38:44 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
len = lws_hdr_total_length(h2n->swsi, (enum lws_token_indexes)n);
|
2017-10-20 17:45:02 +08:00
|
|
|
if (!len || len > (int)sizeof(buf) - 1) {
|
2017-10-13 10:33:02 +08:00
|
|
|
n++;
|
|
|
|
continue;
|
2016-04-10 09:33:54 +08:00
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
if (lws_hdr_copy(h2n->swsi, buf, sizeof buf,
|
2020-12-12 06:21:40 +00:00
|
|
|
(enum lws_token_indexes)n) < 0) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info(" %s !oversize!\n",
|
|
|
|
(char *)c);
|
2018-11-13 16:53:41 +08:00
|
|
|
} else {
|
|
|
|
buf[sizeof(buf) - 1] = '\0';
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info(" %s = %s\n",
|
|
|
|
(char *)c, buf);
|
2018-11-13 16:53:41 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
n++;
|
|
|
|
} while (c);
|
|
|
|
}
|
2014-10-18 12:23:05 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE ||
|
|
|
|
h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
|
|
|
|
"Banning service on CLOSED_REMOTE");
|
|
|
|
break;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
switch (h2n->swsi->h2.h2_state) {
|
2020-04-06 13:22:01 +01:00
|
|
|
case LWS_H2_STATE_IDLE:
|
|
|
|
lws_h2_state(h2n->swsi, LWS_H2_STATE_OPEN);
|
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_STATE_OPEN:
|
2017-12-01 11:09:32 +08:00
|
|
|
if (h2n->swsi->h2.END_STREAM)
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_state(h2n->swsi,
|
|
|
|
LWS_H2_STATE_HALF_CLOSED_REMOTE);
|
|
|
|
break;
|
|
|
|
case LWS_H2_STATE_HALF_CLOSED_LOCAL:
|
2017-12-01 11:09:32 +08:00
|
|
|
if (h2n->swsi->h2.END_STREAM)
|
2021-01-23 05:46:56 +00:00
|
|
|
/*
|
|
|
|
* action the END_STREAM
|
|
|
|
*/
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
|
|
|
|
break;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2021-01-28 19:32:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we already had the END_STREAM along with the END_HEADERS,
|
|
|
|
* we have already transitioned to STATE_CLOSED and we are not
|
|
|
|
* going to be doing anything further on this stream.
|
|
|
|
*
|
|
|
|
* In that case handle the transaction completion and
|
|
|
|
* finalize the stream for the peer
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED &&
|
|
|
|
h2n->swsi->client_mux_substream) {
|
|
|
|
|
|
|
|
lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR,
|
|
|
|
"client done");
|
|
|
|
|
|
|
|
if (lws_http_transaction_completed_client(h2n->swsi))
|
|
|
|
lwsl_debug("tx completed returned close\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (h2n->swsi->client_mux_substream) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: headers: client path (h2 state %s)\n",
|
|
|
|
__func__, lws_wsi_tag(wsi),
|
|
|
|
h2_state_names[h2n->swsi->h2.h2_state]);
|
2018-03-27 09:17:19 +08:00
|
|
|
break;
|
|
|
|
}
|
2018-11-12 15:24:42 +08:00
|
|
|
#endif
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_PATH) ||
|
|
|
|
!lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_METHOD) ||
|
|
|
|
!lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_SCHEME) ||
|
|
|
|
lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_STATUS) ||
|
|
|
|
lws_hdr_extant(h2n->swsi, WSI_TOKEN_CONNECTION)) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Pseudoheader checks");
|
|
|
|
break;
|
|
|
|
}
|
2014-10-18 12:23:05 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (lws_hdr_extant(h2n->swsi, WSI_TOKEN_TE)) {
|
|
|
|
n = lws_hdr_total_length(h2n->swsi, WSI_TOKEN_TE);
|
|
|
|
|
|
|
|
if (n != 8 ||
|
2020-08-18 12:57:58 +01:00
|
|
|
!lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_TE) ||
|
2017-10-13 10:33:02 +08:00
|
|
|
strncmp(lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_TE),
|
2020-12-12 06:21:40 +00:00
|
|
|
"trailers", (unsigned int)n)) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Illegal transfer-encoding");
|
2014-10-29 09:39:08 +08:00
|
|
|
break;
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
2018-09-02 14:35:37 +08:00
|
|
|
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
|
|
|
lws_http_compression_validate(h2n->swsi);
|
|
|
|
#endif
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
p = lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_HTTP_COLON_METHOD);
|
2019-07-29 00:31:41 +01:00
|
|
|
/*
|
|
|
|
* duplicate :path into the individual method uri header
|
|
|
|
* index, so that it looks the same as h1 in the ah
|
|
|
|
*/
|
|
|
|
for (n = 0; n < (int)LWS_ARRAY_SIZE(method_names); n++)
|
2020-08-18 12:57:58 +01:00
|
|
|
if (p && !strcasecmp(p, method_names[n])) {
|
2019-07-29 00:31:41 +01:00
|
|
|
h2n->swsi->http.ah->frag_index[method_index[n]] =
|
|
|
|
h2n->swsi->http.ah->frag_index[
|
2018-11-23 08:47:56 +08:00
|
|
|
WSI_TOKEN_HTTP_COLON_PATH];
|
2019-07-29 00:31:41 +01:00
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2021-01-23 05:46:56 +00:00
|
|
|
{
|
|
|
|
lwsl_debug("%s: setting DEF_ACT from 0x%x\n", __func__,
|
|
|
|
(unsigned int)h2n->swsi->wsistate);
|
|
|
|
lwsi_set_state(h2n->swsi, LRS_DEFERRING_ACTION);
|
|
|
|
lws_callback_on_writable(h2n->swsi);
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_DATA:
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_info("%s: DATA flags 0x%x\n", __func__, h2n->flags);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!h2n->swsi)
|
|
|
|
break;
|
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
if (lws_hdr_total_length(h2n->swsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->h2.END_STREAM &&
|
|
|
|
h2n->swsi->http.rx_content_length &&
|
|
|
|
h2n->swsi->http.rx_content_remain) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_rst_stream(h2n->swsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Not enough rx content");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (h2n->swsi->h2.END_STREAM &&
|
|
|
|
h2n->swsi->h2.h2_state == LWS_H2_STATE_OPEN)
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_h2_state(h2n->swsi,
|
|
|
|
LWS_H2_STATE_HALF_CLOSED_REMOTE);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (h2n->swsi->h2.END_STREAM &&
|
|
|
|
h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_LOCAL)
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2018-04-05 20:48:08 +08:00
|
|
|
/*
|
|
|
|
* client... remote END_STREAM implies we weren't going to
|
|
|
|
* send anything else anyway.
|
|
|
|
*/
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (h2n->swsi->client_mux_substream &&
|
2019-10-16 15:08:25 +01:00
|
|
|
(h2n->flags & LWS_H2_FLAG_END_STREAM)) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: DATA: end stream\n",
|
|
|
|
__func__, lws_wsi_tag(h2n->swsi));
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
if (h2n->swsi->h2.h2_state == LWS_H2_STATE_OPEN) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_h2_state(h2n->swsi,
|
|
|
|
LWS_H2_STATE_HALF_CLOSED_REMOTE);
|
2018-04-02 11:55:17 +08:00
|
|
|
// lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR,
|
|
|
|
// "client done");
|
|
|
|
|
|
|
|
// if (lws_http_transaction_completed_client(h2n->swsi))
|
|
|
|
// lwsl_debug("tx completed returned close\n");
|
|
|
|
}
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2018-04-05 20:48:08 +08:00
|
|
|
//if (h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_LOCAL)
|
|
|
|
{
|
2018-03-27 09:17:19 +08:00
|
|
|
lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
|
|
|
|
|
|
|
|
lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR,
|
|
|
|
"client done");
|
|
|
|
|
|
|
|
if (lws_http_transaction_completed_client(h2n->swsi))
|
|
|
|
lwsl_debug("tx completed returned close\n");
|
|
|
|
}
|
|
|
|
}
|
2018-11-12 15:24:42 +08:00
|
|
|
#endif
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_PING:
|
2020-01-02 08:32:23 +00:00
|
|
|
if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)
|
2019-09-18 13:09:32 +01:00
|
|
|
lws_validity_confirmed(wsi);
|
2020-01-02 08:32:23 +00:00
|
|
|
else {
|
|
|
|
/* they're sending us a ping request */
|
2018-10-10 13:54:43 +08:00
|
|
|
struct lws_h2_protocol_send *pps =
|
|
|
|
lws_h2_new_pps(LWS_H2_PPS_PONG);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!pps)
|
|
|
|
return 1;
|
2018-10-10 13:54:43 +08:00
|
|
|
|
|
|
|
lwsl_info("rx ping, preparing pong\n");
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
memcpy(pps->u.ping.ping_payload, h2n->ping_payload, 8);
|
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_WINDOW_UPDATE:
|
2020-01-02 08:32:23 +00:00
|
|
|
/*
|
|
|
|
* We only have an unsigned 31-bit (positive) increment possible
|
|
|
|
*/
|
2018-11-03 14:47:48 +08:00
|
|
|
h2n->hpack_e_dep &= ~(1u << 31);
|
2019-11-05 21:00:45 +00:00
|
|
|
lwsl_info("WINDOW_UPDATE: sid %u %u (0x%x)\n",
|
|
|
|
(unsigned int)h2n->sid,
|
|
|
|
(unsigned int)h2n->hpack_e_dep,
|
|
|
|
(unsigned int)h2n->hpack_e_dep);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (h2n->sid)
|
|
|
|
eff_wsi = h2n->swsi;
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!eff_wsi) {
|
|
|
|
if (h2n->sid > h2n->highest_sid_opened)
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"alien sid");
|
|
|
|
break; /* ignore */
|
2014-10-08 12:00:53 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +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 (eff_wsi->a.vhost->options &
|
2019-07-08 08:48:58 +01:00
|
|
|
LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW &&
|
2019-12-26 02:35:41 +00:00
|
|
|
(uint64_t)eff_wsi->txc.tx_cr + (uint64_t)h2n->hpack_e_dep >
|
2019-07-08 08:48:58 +01:00
|
|
|
(uint64_t)0x7fffffff)
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->hpack_e_dep = (uint32_t)(0x7fffffff - eff_wsi->txc.tx_cr);
|
2019-07-08 08:48:58 +01:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
if ((uint64_t)eff_wsi->txc.tx_cr + (uint64_t)h2n->hpack_e_dep >
|
2017-10-13 10:33:02 +08:00
|
|
|
(uint64_t)0x7fffffff) {
|
2021-02-26 11:38:45 +00:00
|
|
|
lwsl_warn("%s: WINDOW_UPDATE 0x%llx + 0x%llx = 0x%llx, too high\n",
|
|
|
|
__func__, (unsigned long long)eff_wsi->txc.tx_cr,
|
|
|
|
(unsigned long long)h2n->hpack_e_dep,
|
|
|
|
(unsigned long long)eff_wsi->txc.tx_cr + (unsigned long long)h2n->hpack_e_dep);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (h2n->sid)
|
|
|
|
lws_h2_rst_stream(h2n->swsi,
|
|
|
|
H2_ERR_FLOW_CONTROL_ERROR,
|
|
|
|
"Flow control exceeded max");
|
|
|
|
else
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_FLOW_CONTROL_ERROR,
|
|
|
|
"Flow control exceeded max");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!h2n->hpack_e_dep) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Zero length window update");
|
|
|
|
break;
|
|
|
|
}
|
2019-12-26 02:35:41 +00:00
|
|
|
n = eff_wsi->txc.tx_cr;
|
2020-12-12 06:21:40 +00:00
|
|
|
eff_wsi->txc.tx_cr += (int32_t)h2n->hpack_e_dep;
|
2019-12-26 02:35:41 +00:00
|
|
|
|
|
|
|
lws_wsi_txc_report_manual_txcr_in(eff_wsi,
|
|
|
|
(int32_t)h2n->hpack_e_dep);
|
|
|
|
|
|
|
|
lws_wsi_txc_describe(&eff_wsi->txc, "WINDOW_UPDATE in",
|
|
|
|
eff_wsi->mux.my_sid);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
if (n <= 0 && eff_wsi->txc.tx_cr <= 0)
|
2017-10-13 10:33:02 +08:00
|
|
|
/* it helps, but won't change sendability for anyone */
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
2019-12-26 02:35:41 +00:00
|
|
|
* It may have changed sendability (depends on SID 0 tx credit
|
|
|
|
* too)... for us and any children waiting on us... reassess
|
|
|
|
* blockage for all children first
|
2017-10-13 10:33:02 +08:00
|
|
|
*/
|
2019-12-23 11:31:57 +00:00
|
|
|
lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_callback_on_writable(w);
|
2019-12-23 11:31:57 +00:00
|
|
|
} lws_end_foreach_ll(w, mux.sibling_list);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
if (eff_wsi->txc.skint &&
|
|
|
|
!lws_wsi_txc_check_skint(&eff_wsi->txc,
|
|
|
|
lws_h2_tx_cr_get(eff_wsi)))
|
|
|
|
/*
|
|
|
|
* This one became un-skint, schedule a writeable
|
|
|
|
* callback
|
|
|
|
*/
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_callback_on_writable(eff_wsi);
|
2019-12-26 02:35:41 +00:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_GOAWAY:
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_notice("GOAWAY: last sid %u, error 0x%08X, string '%s'\n",
|
2019-10-17 11:08:47 +01:00
|
|
|
(unsigned int)h2n->goaway_last_sid,
|
|
|
|
(unsigned int)h2n->goaway_err, h2n->goaway_str);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
2018-03-11 11:26:06 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_RST_STREAM:
|
2019-11-05 21:00:45 +00:00
|
|
|
lwsl_info("LWS_H2_FRAME_TYPE_RST_STREAM: sid %u: reason 0x%x\n",
|
2020-01-02 08:32:23 +00:00
|
|
|
(unsigned int)h2n->sid,
|
|
|
|
(unsigned int)h2n->hpack_e_dep);
|
2018-03-11 11:26:06 +08:00
|
|
|
break;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */
|
2014-10-08 12:00:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-07 07:20:47 +08:00
|
|
|
/*
|
|
|
|
* This may want to send something on the network wsi, which may be in the
|
|
|
|
* middle of a partial send. PPS sends are OK because they are queued to
|
|
|
|
* go through the WRITABLE handler already.
|
|
|
|
*
|
|
|
|
* The read parser for the network wsi has no choice but to parse its stream
|
|
|
|
* anyway, because otherwise it will not be able to get tx credit window
|
|
|
|
* messages.
|
|
|
|
*
|
|
|
|
* Therefore if we will send non-PPS, ie, lws_http_action() for a stream
|
|
|
|
* wsi, we must change its state and handle it as a priority in the
|
|
|
|
* POLLOUT handler instead of writing it here.
|
2018-03-11 11:26:06 +08:00
|
|
|
*
|
|
|
|
* About closing... for the main network wsi, it should return nonzero to
|
|
|
|
* close it all. If it needs to close an swsi, it can do it here.
|
2017-12-07 07:20:47 +08:00
|
|
|
*/
|
2017-10-13 10:33:02 +08:00
|
|
|
int
|
2020-12-20 08:34:23 +00:00
|
|
|
lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t _inlen,
|
2017-11-25 10:10:33 +08:00
|
|
|
lws_filepos_t *inused)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
2017-12-01 11:09:32 +08:00
|
|
|
struct lws_h2_netconn *h2n = wsi->h2.h2n;
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws_h2_protocol_send *pps;
|
2020-12-20 08:34:23 +00:00
|
|
|
unsigned char c, *oldin = in, *iend = in + (size_t)_inlen;
|
2018-03-27 09:17:19 +08:00
|
|
|
int n, m;
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!h2n)
|
2017-11-25 10:10:33 +08:00
|
|
|
goto fail;
|
|
|
|
|
2020-12-20 08:34:23 +00:00
|
|
|
while (in < iend) {
|
2017-11-25 10:10:33 +08:00
|
|
|
|
|
|
|
c = *in++;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
switch (lwsi_state(wsi)) {
|
|
|
|
case LRS_H2_AWAIT_PREFACE:
|
2018-02-19 05:31:14 +08:00
|
|
|
if (preface[h2n->count++] != c)
|
|
|
|
goto fail;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
if (preface[h2n->count])
|
|
|
|
break;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("http2: %s: established\n", lws_wsi_tag(wsi));
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_H2_AWAIT_SETTINGS);
|
2019-09-18 13:09:32 +01:00
|
|
|
lws_validity_confirmed(wsi);
|
2018-02-19 05:31:14 +08:00
|
|
|
h2n->count = 0;
|
2019-12-26 02:35:41 +00:00
|
|
|
wsi->txc.tx_cr = 65535;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
|
|
|
/*
|
2018-02-19 05:31:14 +08:00
|
|
|
* we must send a settings frame -- empty one is OK...
|
|
|
|
* that must be the first thing sent by server
|
|
|
|
* and the peer must send a SETTINGS with ACK flag...
|
2014-10-18 18:54:04 +08:00
|
|
|
*/
|
2018-02-19 05:31:14 +08:00
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS);
|
|
|
|
if (!pps)
|
|
|
|
goto fail;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
break;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
case LRS_H2_WAITING_TO_SEND_HEADERS:
|
|
|
|
case LRS_ESTABLISHED:
|
|
|
|
case LRS_H2_AWAIT_SETTINGS:
|
2020-12-01 13:11:28 +00:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
if (h2n->frame_state != LWS_H2_FRAME_HEADER_LENGTH)
|
|
|
|
goto try_frame_start;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
/*
|
|
|
|
* post-header, preamble / payload / padding part
|
|
|
|
*/
|
|
|
|
h2n->count++;
|
|
|
|
|
2020-12-01 13:11:28 +00:00
|
|
|
if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */
|
2021-06-17 10:07:04 +01:00
|
|
|
//lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
|
2020-12-01 13:11:28 +00:00
|
|
|
goto frame_end;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
if (h2n->flags & LWS_H2_FLAG_PADDED &&
|
|
|
|
!h2n->pad_length) {
|
2018-02-19 05:31:14 +08:00
|
|
|
/*
|
|
|
|
* Get the padding count... actual padding is
|
|
|
|
* at the end of the frame.
|
|
|
|
*/
|
|
|
|
h2n->padding = c;
|
|
|
|
h2n->pad_length = 1;
|
|
|
|
h2n->preamble++;
|
|
|
|
|
|
|
|
if (h2n->padding > h2n->length - 1)
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_h2_goaway(wsi,
|
|
|
|
H2_ERR_PROTOCOL_ERROR,
|
2018-02-19 05:31:14 +08:00
|
|
|
"execssive padding");
|
2017-10-13 10:33:02 +08:00
|
|
|
break; /* we consumed this */
|
|
|
|
}
|
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
if (h2n->flags & LWS_H2_FLAG_PRIORITY &&
|
|
|
|
!h2n->collected_priority) {
|
|
|
|
/* going to be 5 preamble bytes */
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
lwsl_debug("PRIORITY FLAG: 0x%x\n", c);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
if (h2n->preamble++ - h2n->pad_length < 4) {
|
|
|
|
h2n->dep = ((h2n->dep) << 8) | c;
|
|
|
|
break; /* we consumed this */
|
|
|
|
}
|
|
|
|
h2n->weight_temp = c;
|
|
|
|
h2n->collected_priority = 1;
|
|
|
|
lwsl_debug("PRI FL: dep 0x%x, weight 0x%02X\n",
|
2020-01-02 08:32:23 +00:00
|
|
|
(unsigned int)h2n->dep,
|
|
|
|
h2n->weight_temp);
|
2018-02-19 05:31:14 +08:00
|
|
|
break; /* we consumed this */
|
|
|
|
}
|
2018-11-23 08:47:56 +08:00
|
|
|
if (h2n->padding && h2n->count >
|
|
|
|
(h2n->length - h2n->padding)) {
|
2018-02-19 05:31:14 +08:00
|
|
|
if (c) {
|
2019-12-26 02:35:41 +00:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
2018-02-19 05:31:14 +08:00
|
|
|
"nonzero padding");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto frame_end;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
/* applies to wsi->h2.swsi which may be wsi */
|
|
|
|
switch(h2n->type) {
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_SETTINGS:
|
2020-12-12 06:21:40 +00:00
|
|
|
n = (int)(h2n->count - 1u - h2n->preamble) %
|
2018-02-19 05:31:14 +08:00
|
|
|
LWS_H2_SETTINGS_LEN;
|
|
|
|
h2n->one_setting[n] = c;
|
|
|
|
if (n != LWS_H2_SETTINGS_LEN - 1)
|
|
|
|
break;
|
2019-12-26 02:35:41 +00:00
|
|
|
lws_h2_settings(wsi, &h2n->peer_set,
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->one_setting,
|
2018-02-19 05:31:14 +08:00
|
|
|
LWS_H2_SETTINGS_LEN);
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_CONTINUATION:
|
|
|
|
case LWS_H2_FRAME_TYPE_HEADERS:
|
|
|
|
if (!h2n->swsi)
|
|
|
|
break;
|
|
|
|
if (lws_hpack_interpret(h2n->swsi, c)) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("%s: hpack failed\n",
|
|
|
|
__func__);
|
2018-02-19 05:31:14 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_GOAWAY:
|
|
|
|
switch (h2n->inside++) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
h2n->goaway_last_sid <<= 8;
|
|
|
|
h2n->goaway_last_sid |= c;
|
|
|
|
h2n->goaway_str[0] = '\0';
|
|
|
|
break;
|
2018-02-03 13:53:45 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
case 7:
|
|
|
|
h2n->goaway_err <<= 8;
|
|
|
|
h2n->goaway_err |= c;
|
|
|
|
break;
|
2018-02-03 13:53:45 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
default:
|
|
|
|
if (h2n->inside - 9 <
|
|
|
|
sizeof(h2n->goaway_str) - 1)
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->goaway_str[
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->inside - 9] = (char)c;
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->goaway_str[
|
|
|
|
sizeof(h2n->goaway_str) - 1] = '\0';
|
2018-02-19 05:31:14 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_DATA:
|
2017-11-25 10:10:33 +08:00
|
|
|
|
2020-12-17 22:16:57 +00:00
|
|
|
// lwsl_info("%s: LWS_H2_FRAME_TYPE_DATA: fl 0x%x\n",
|
|
|
|
// __func__, h2n->flags);
|
2018-04-02 11:55:17 +08:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
/*
|
|
|
|
* let the network wsi live a bit longer if
|
|
|
|
* subs are active... our frame may take a long
|
|
|
|
* time to chew through
|
|
|
|
*/
|
2019-01-30 20:59:56 +08:00
|
|
|
if (!wsi->immortal_substream_count)
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_set_timeout(wsi,
|
2019-09-13 10:33:24 +01:00
|
|
|
PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.vhost->keepalive_timeout ?
|
|
|
|
wsi->a.vhost->keepalive_timeout : 31);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
if (!h2n->swsi)
|
|
|
|
break;
|
2017-11-14 07:35:05 +08:00
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
if (lws_buflist_next_segment_len(
|
|
|
|
&h2n->swsi->buflist, NULL))
|
|
|
|
lwsl_info("%s: substream has pending\n",
|
|
|
|
__func__);
|
2018-04-17 15:35:15 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
if (lwsi_role_http(h2n->swsi) &&
|
|
|
|
lwsi_state(h2n->swsi) == LRS_ESTABLISHED) {
|
|
|
|
lwsi_set_state(h2n->swsi, LRS_BODY);
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s to LRS_BODY\n",
|
|
|
|
__func__, lws_wsi_tag(h2n->swsi));
|
2018-02-19 05:31:14 +08:00
|
|
|
}
|
2017-11-25 10:10:33 +08:00
|
|
|
|
2021-08-09 14:14:06 +01:00
|
|
|
/*
|
|
|
|
* in + length may cover multiple frames, we
|
|
|
|
* can only consider the length of the DATA
|
|
|
|
* in front of us
|
|
|
|
*/
|
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
if (lws_hdr_total_length(h2n->swsi,
|
2018-11-23 08:47:56 +08:00
|
|
|
WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
|
2018-02-19 05:31:14 +08:00
|
|
|
h2n->swsi->http.rx_content_length &&
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->swsi->http.rx_content_remain <
|
2021-08-09 14:14:06 +01:00
|
|
|
h2n->length && /* last */
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->inside < h2n->length) {
|
2020-12-20 08:34:23 +00:00
|
|
|
|
2021-03-02 16:34:33 +00:00
|
|
|
lwsl_warn("%s: %lu %lu %lu %lu\n", __func__,
|
|
|
|
(unsigned long)h2n->swsi->http.rx_content_remain,
|
2021-08-09 14:14:06 +01:00
|
|
|
(unsigned long)(lws_ptr_diff_size_t(iend, in) + 1),
|
2021-03-02 16:34:33 +00:00
|
|
|
(unsigned long)h2n->inside, (unsigned long)h2n->length);
|
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
/* unread data in frame */
|
|
|
|
lws_h2_goaway(wsi,
|
|
|
|
H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"More rx than content_length told");
|
2018-02-19 05:31:14 +08:00
|
|
|
break;
|
|
|
|
}
|
2018-02-06 09:58:48 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
/*
|
2018-03-27 09:17:19 +08:00
|
|
|
* We operate on a frame. The RX we have at
|
|
|
|
* hand may exceed the current frame.
|
2018-02-19 05:31:14 +08:00
|
|
|
*/
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2020-12-20 08:34:23 +00:00
|
|
|
n = (int)lws_ptr_diff_size_t(iend, in) + 1;
|
2018-02-19 05:31:14 +08:00
|
|
|
if (n > (int)(h2n->length - h2n->count + 1)) {
|
2020-12-12 06:21:40 +00:00
|
|
|
if (h2n->count > h2n->length)
|
|
|
|
goto close_swsi_and_return;
|
|
|
|
n = (int)(h2n->length - h2n->count) + 1;
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_debug("---- restricting len to %d "
|
2020-12-20 08:34:23 +00:00
|
|
|
"\n", n);
|
2018-02-19 05:31:14 +08:00
|
|
|
}
|
2019-08-18 05:04:15 +01:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2019-12-23 11:31:57 +00:00
|
|
|
if (h2n->swsi->client_mux_substream) {
|
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 (!h2n->swsi->a.protocol) {
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_err("%s: %p doesn't have protocol\n",
|
|
|
|
__func__, lws_wsi_tag(h2n->swsi));
|
2019-08-26 18:41:40 +01:00
|
|
|
m = 1;
|
2019-12-26 02:35:41 +00:00
|
|
|
} else {
|
|
|
|
h2n->swsi->txc.peer_tx_cr_est -= n;
|
|
|
|
wsi->txc.peer_tx_cr_est -= n;
|
|
|
|
lws_wsi_txc_describe(&h2n->swsi->txc,
|
|
|
|
__func__,
|
|
|
|
h2n->swsi->mux.my_sid);
|
2018-03-27 09:17:19 +08:00
|
|
|
m = user_callback_handle_rxflow(
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
h2n->swsi->a.protocol->callback,
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->swsi,
|
|
|
|
LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
|
|
|
|
h2n->swsi->user_space,
|
2020-12-12 06:21:40 +00:00
|
|
|
in - 1, (unsigned int)n);
|
2019-12-26 02:35:41 +00:00
|
|
|
}
|
2019-08-26 18:41:40 +01:00
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
in += n - 1;
|
2020-12-20 08:34:23 +00:00
|
|
|
h2n->inside += (unsigned int)n;
|
|
|
|
h2n->count += (unsigned int)n - 1;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
if (m) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("RECEIVE_CLIENT_HTTP "
|
|
|
|
"closed it\n");
|
2018-03-27 09:17:19 +08:00
|
|
|
goto close_swsi_and_return;
|
|
|
|
}
|
|
|
|
|
2021-08-30 14:18:14 +01:00
|
|
|
goto do_windows;
|
2019-12-26 02:35:41 +00:00
|
|
|
}
|
2018-11-12 15:24:42 +08:00
|
|
|
#endif
|
2019-12-26 02:35:41 +00:00
|
|
|
if (lwsi_state(h2n->swsi) == LRS_DEFERRING_ACTION) {
|
|
|
|
m = lws_buflist_append_segment(
|
2020-12-12 06:21:40 +00:00
|
|
|
&h2n->swsi->buflist, in - 1, (unsigned int)n);
|
2019-12-26 02:35:41 +00:00
|
|
|
if (m < 0)
|
|
|
|
return -1;
|
2021-01-18 14:20:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since we're in an open-ended
|
|
|
|
* DEFERRING_ACTION, don't add this swsi
|
|
|
|
* to the pt list of wsi holding buflist
|
|
|
|
* content yet, we are not in a position
|
|
|
|
* to consume it until we get out of
|
|
|
|
* DEFERRING_ACTION.
|
|
|
|
*/
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
in += n - 1;
|
2020-12-20 08:34:23 +00:00
|
|
|
h2n->inside += (unsigned int)n;
|
|
|
|
h2n->count += (unsigned int)n - 1;
|
2019-12-26 02:35:41 +00:00
|
|
|
|
|
|
|
lwsl_debug("%s: deferred %d\n", __func__, n);
|
|
|
|
goto do_windows;
|
|
|
|
}
|
|
|
|
|
|
|
|
h2n->swsi->outer_will_close = 1;
|
|
|
|
/*
|
|
|
|
* choose the length for this go so that we end at
|
|
|
|
* the frame boundary, in the case there is already
|
|
|
|
* more waiting leave it for next time around
|
|
|
|
*/
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = lws_read_h1(h2n->swsi, in - 1, (unsigned int)n);
|
2019-12-26 02:35:41 +00:00
|
|
|
// lwsl_notice("%s: lws_read_h1 %d\n", __func__, n);
|
|
|
|
h2n->swsi->outer_will_close = 0;
|
|
|
|
/*
|
|
|
|
* can return 0 in POST body with
|
|
|
|
* content len exhausted somehow.
|
|
|
|
*/
|
|
|
|
if (n < 0 ||
|
2020-12-20 08:34:23 +00:00
|
|
|
(!n && h2n->swsi->http.content_length_given && !lws_buflist_next_segment_len(
|
2019-12-26 02:35:41 +00:00
|
|
|
&wsi->buflist, NULL))) {
|
|
|
|
lwsl_info("%s: lws_read_h1 told %d %u / %u\n",
|
|
|
|
__func__, n,
|
|
|
|
(unsigned int)h2n->count,
|
|
|
|
(unsigned int)h2n->length);
|
|
|
|
in += h2n->length - h2n->count;
|
|
|
|
h2n->inside = h2n->length;
|
|
|
|
h2n->count = h2n->length - 1;
|
|
|
|
|
|
|
|
//if (n < 0)
|
|
|
|
// goto already_closed_swsi;
|
|
|
|
goto close_swsi_and_return;
|
2018-03-27 09:17:19 +08:00
|
|
|
}
|
2018-02-19 05:31:14 +08:00
|
|
|
|
2020-12-20 08:34:23 +00:00
|
|
|
lwsl_info("%s: lws_read_h1 telling %d %u / %u\n",
|
|
|
|
__func__, n,
|
|
|
|
(unsigned int)h2n->count,
|
|
|
|
(unsigned int)h2n->length);
|
|
|
|
|
2025-01-16 11:40:26 +00:00
|
|
|
if (n) {
|
|
|
|
in += (unsigned int)n - 1;
|
|
|
|
h2n->inside += (unsigned int)n;
|
|
|
|
h2n->count += (unsigned int)n - 1;
|
2020-12-20 08:34:23 +00:00
|
|
|
|
2025-01-16 11:40:26 +00:00
|
|
|
h2n->swsi->txc.peer_tx_cr_est -= n;
|
|
|
|
wsi->txc.peer_tx_cr_est -= n;
|
|
|
|
}
|
2019-12-26 02:35:41 +00:00
|
|
|
|
2018-04-17 11:43:20 +08:00
|
|
|
do_windows:
|
2018-02-19 05:31:14 +08:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
|
|
|
if (!(h2n->swsi->flags & LCCSCF_H2_MANUAL_RXFLOW))
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The default behaviour is we just keep
|
|
|
|
* cranking the other side's tx credit
|
|
|
|
* back up, for simple bulk transfer as
|
|
|
|
* fast as we can take it
|
|
|
|
*/
|
|
|
|
|
2021-08-30 14:18:14 +01:00
|
|
|
m = n + 65536;
|
2018-02-19 05:31:14 +08:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
/* update both the stream and nwsi */
|
2018-02-19 05:31:14 +08:00
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
lws_h2_update_peer_txcredit_thresh(h2n->swsi,
|
|
|
|
h2n->sid, m, m);
|
2018-02-19 05:31:14 +08:00
|
|
|
}
|
2019-12-26 02:35:41 +00:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* If he's handling it himself, only
|
|
|
|
* repair the nwsi credit but allow the
|
|
|
|
* stream credit to run down until the
|
|
|
|
* user code deals with it
|
|
|
|
*/
|
|
|
|
lws_h2_update_peer_txcredit(wsi, 0, n);
|
|
|
|
h2n->swsi->txc.manual = 1;
|
2018-02-19 05:31:14 +08:00
|
|
|
}
|
2019-12-26 02:35:41 +00:00
|
|
|
#endif
|
2018-02-19 05:31:14 +08:00
|
|
|
break;
|
2018-02-06 09:58:48 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_PRIORITY:
|
|
|
|
if (h2n->count <= 4) {
|
|
|
|
h2n->dep <<= 8;
|
|
|
|
h2n->dep |= c;
|
2020-01-02 08:32:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
h2n->weight_temp = c;
|
|
|
|
lwsl_info("PRIORITY: dep 0x%x, weight 0x%02X\n",
|
|
|
|
(unsigned int)h2n->dep, h2n->weight_temp);
|
|
|
|
|
|
|
|
if ((h2n->dep & ~(1u << 31)) == h2n->sid) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"cant depend on own sid");
|
|
|
|
break;
|
2018-02-19 05:31:14 +08:00
|
|
|
}
|
|
|
|
break;
|
2017-11-24 10:54:59 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_RST_STREAM:
|
2018-03-11 11:26:06 +08:00
|
|
|
h2n->hpack_e_dep <<= 8;
|
|
|
|
h2n->hpack_e_dep |= c;
|
2018-02-19 05:31:14 +08:00
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_PUSH_PROMISE:
|
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_PING:
|
|
|
|
if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK) { // ack
|
|
|
|
} else { /* they're sending us a ping request */
|
|
|
|
if (h2n->count > 8)
|
|
|
|
return 1;
|
|
|
|
h2n->ping_payload[h2n->count - 1] = c;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2018-02-19 05:31:14 +08:00
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_WINDOW_UPDATE:
|
|
|
|
h2n->hpack_e_dep <<= 8;
|
|
|
|
h2n->hpack_e_dep |= c;
|
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */
|
2021-06-17 10:07:04 +01:00
|
|
|
//lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
|
2020-12-01 13:11:28 +00:00
|
|
|
h2n->count++;
|
2018-02-19 05:31:14 +08:00
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
default:
|
|
|
|
lwsl_notice("%s: unhandled frame type %d\n",
|
|
|
|
__func__, h2n->type);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
frame_end:
|
2018-04-02 11:55:17 +08:00
|
|
|
if (h2n->count > h2n->length) {
|
2020-12-01 13:11:28 +00:00
|
|
|
lwsl_notice("%s: count > length %u %u (type %d)\n",
|
2019-10-17 11:08:47 +01:00
|
|
|
__func__, (unsigned int)h2n->count,
|
2020-12-01 13:11:28 +00:00
|
|
|
(unsigned int)h2n->length, h2n->type);
|
|
|
|
|
|
|
|
} else
|
|
|
|
if (h2n->count != h2n->length)
|
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
/*
|
|
|
|
* end of frame just happened
|
|
|
|
*/
|
2021-06-17 10:07:04 +01:00
|
|
|
n = lws_h2_parse_end_of_frame(wsi);
|
|
|
|
if (n == 2) {
|
|
|
|
*inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);
|
|
|
|
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
if (n)
|
2018-02-19 05:31:14 +08:00
|
|
|
goto fail;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
try_frame_start:
|
2018-02-19 05:31:14 +08:00
|
|
|
if (h2n->frame_state <= 8) {
|
|
|
|
|
|
|
|
switch (h2n->frame_state++) {
|
|
|
|
case 0:
|
|
|
|
h2n->pad_length = 0;
|
|
|
|
h2n->collected_priority = 0;
|
|
|
|
h2n->padding = 0;
|
|
|
|
h2n->preamble = 0;
|
|
|
|
h2n->length = c;
|
|
|
|
h2n->inside = 0;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
h2n->length <<= 8;
|
|
|
|
h2n->length |= c;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
h2n->type = c;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
h2n->flags = c;
|
|
|
|
break;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
case 7:
|
|
|
|
case 8:
|
|
|
|
h2n->sid <<= 8;
|
|
|
|
h2n->sid |= c;
|
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2018-02-19 05:31:14 +08:00
|
|
|
|
2020-12-01 13:11:28 +00:00
|
|
|
if (h2n->frame_state == LWS_H2_FRAME_HEADER_LENGTH &&
|
|
|
|
lws_h2_parse_frame_header(wsi))
|
|
|
|
goto fail;
|
2018-02-19 05:31:14 +08:00
|
|
|
break;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
default:
|
2020-12-01 13:11:28 +00:00
|
|
|
if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */
|
2021-06-17 10:07:04 +01:00
|
|
|
//lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
|
2020-12-01 13:11:28 +00:00
|
|
|
h2n->count++;
|
|
|
|
}
|
2018-04-02 11:55:17 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-11-25 10:10:33 +08:00
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
*inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);
|
2017-11-25 10:10:33 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
return 0;
|
2017-11-25 10:10:33 +08:00
|
|
|
|
2018-03-11 11:26:06 +08:00
|
|
|
close_swsi_and_return:
|
|
|
|
|
|
|
|
lws_close_free_wsi(h2n->swsi, 0, "close_swsi_and_return");
|
|
|
|
h2n->swsi = NULL;
|
|
|
|
h2n->frame_state = 0;
|
|
|
|
h2n->count = 0;
|
|
|
|
|
2018-04-25 08:42:18 +08:00
|
|
|
// already_closed_swsi:
|
2020-12-12 06:21:40 +00:00
|
|
|
*inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);
|
2018-03-11 11:26:06 +08:00
|
|
|
|
|
|
|
return 2;
|
|
|
|
|
2017-11-25 10:10:33 +08:00
|
|
|
fail:
|
2020-12-12 06:21:40 +00:00
|
|
|
*inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);
|
2017-11-25 10:10:33 +08:00
|
|
|
|
|
|
|
return 1;
|
2014-10-22 15:37:28 +08:00
|
|
|
}
|
|
|
|
|
2019-10-03 08:31:34 -07:00
|
|
|
#if defined(LWS_WITH_CLIENT)
|
2018-03-27 09:17:19 +08:00
|
|
|
int
|
|
|
|
lws_h2_client_handshake(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];
|
2019-10-16 15:08:25 +01:00
|
|
|
uint8_t *buf, *start, *p, *p1, *end;
|
2018-03-27 09:17:19 +08:00
|
|
|
char *meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD),
|
2020-08-19 07:11:59 +01:00
|
|
|
*uri = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI), *simp;
|
2018-03-27 09:17:19 +08:00
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
2021-06-17 10:07:04 +01:00
|
|
|
const char *path = "/";
|
2019-10-02 10:49:18 -07:00
|
|
|
int n, m;
|
2018-03-27 09:17:19 +08:00
|
|
|
/*
|
|
|
|
* The identifier of a newly established stream MUST be numerically
|
|
|
|
* greater than all streams that the initiating endpoint has opened or
|
|
|
|
* reserved. This governs streams that are opened using a HEADERS frame
|
|
|
|
* and streams that are reserved using PUSH_PROMISE. An endpoint that
|
|
|
|
* receives an unexpected stream identifier MUST respond with a
|
|
|
|
* connection error (Section 5.4.1) of type PROTOCOL_ERROR.
|
|
|
|
*/
|
2020-12-12 06:21:40 +00:00
|
|
|
unsigned int sid = nwsi->h2.h2n->highest_sid_opened + 2;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
lwsl_debug("%s\n", __func__);
|
|
|
|
|
2020-05-04 08:26:48 +01:00
|
|
|
/*
|
|
|
|
* We MUST allocate our sid here at the point we're about to send the
|
|
|
|
* stream open. It's because we don't know the order in which multiple
|
|
|
|
* open streams will send their headers... in h2, sending the headers
|
|
|
|
* is the point the stream is opened. The peer requires that we only
|
|
|
|
* open streams in ascending sid order
|
|
|
|
*/
|
|
|
|
|
|
|
|
wsi->mux.my_sid = nwsi->h2.h2n->highest_sid_opened = sid;
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_info("%s: %s: assigning SID %d at header send\n", __func__,
|
|
|
|
lws_wsi_tag(wsi), sid);
|
2020-05-04 08:26:48 +01:00
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
lwsl_info("%s: CLIENT_WAITING_TO_SEND_HEADERS: pollout (sid %d)\n",
|
2019-12-23 11:31:57 +00:00
|
|
|
__func__, wsi->mux.my_sid);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2018-04-16 19:52:28 +08:00
|
|
|
p = start = buf = pt->serv_buf + LWS_PRE;
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
end = start + (wsi->a.context->pt_serv_buf_size / 2) - LWS_PRE - 1;
|
2018-04-16 19:52:28 +08:00
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
/* it's time for us to send our client stream headers */
|
|
|
|
|
|
|
|
if (!meth)
|
|
|
|
meth = "GET";
|
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
/* h2 pseudoheaders must be in a bunch at the start */
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_METHOD,
|
|
|
|
(unsigned char *)meth,
|
2018-04-16 19:52:28 +08:00
|
|
|
(int)strlen(meth), &p, end))
|
|
|
|
goto fail_length;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_SCHEME,
|
2019-10-02 10:49:18 -07:00
|
|
|
(unsigned char *)"https", 5,
|
2018-03-27 09:17:19 +08:00
|
|
|
&p, end))
|
2018-04-16 19:52:28 +08:00
|
|
|
goto fail_length;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
|
2020-08-19 07:11:59 +01:00
|
|
|
n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI);
|
2021-06-17 10:07:04 +01:00
|
|
|
if (n)
|
|
|
|
path = uri;
|
|
|
|
else
|
|
|
|
if (wsi->stash && wsi->stash->cis[CIS_PATH]) {
|
|
|
|
path = wsi->stash->cis[CIS_PATH];
|
|
|
|
n = (int)strlen(path);
|
|
|
|
} else
|
|
|
|
n = 1;
|
|
|
|
|
|
|
|
if (n > 1 && path[0] == '/' && path[1] == '/') {
|
|
|
|
path++;
|
|
|
|
n--;
|
|
|
|
}
|
|
|
|
|
2020-08-19 07:11:59 +01:00
|
|
|
if (n && lws_add_http_header_by_token(wsi,
|
2018-03-27 09:17:19 +08:00
|
|
|
WSI_TOKEN_HTTP_COLON_PATH,
|
2021-06-17 10:07:04 +01:00
|
|
|
(unsigned char *)path, n, &p, end))
|
2018-04-16 19:52:28 +08:00
|
|
|
goto fail_length;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_HOST);
|
|
|
|
simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST);
|
|
|
|
if (!n && wsi->stash && wsi->stash->cis[CIS_ADDRESS]) {
|
|
|
|
n = (int)strlen(wsi->stash->cis[CIS_ADDRESS]);
|
|
|
|
simp = wsi->stash->cis[CIS_ADDRESS];
|
|
|
|
}
|
|
|
|
|
|
|
|
// n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
|
|
|
|
// simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
|
|
|
|
#if 0
|
2020-08-19 07:11:59 +01:00
|
|
|
if (n && simp && lws_add_http_header_by_token(wsi,
|
2018-03-27 09:17:19 +08:00
|
|
|
WSI_TOKEN_HTTP_COLON_AUTHORITY,
|
2020-08-19 07:11:59 +01:00
|
|
|
(unsigned char *)simp, n, &p, end))
|
2018-04-16 19:52:28 +08:00
|
|
|
goto fail_length;
|
2021-06-17 10:07:04 +01:00
|
|
|
#endif
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2020-08-19 07:11:59 +01:00
|
|
|
|
2021-06-17 10:07:04 +01:00
|
|
|
if (/*!wsi->client_h2_alpn && */n && simp &&
|
2020-05-05 12:17:27 +01:00
|
|
|
lws_add_http_header_by_token(wsi, WSI_TOKEN_HOST,
|
2020-08-19 07:11:59 +01:00
|
|
|
(unsigned char *)simp, n, &p, end))
|
2019-10-02 10:49:18 -07:00
|
|
|
goto fail_length;
|
|
|
|
|
|
|
|
|
2019-10-07 14:28:18 +01:00
|
|
|
if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME) {
|
|
|
|
p1 = lws_http_multipart_headers(wsi, p);
|
|
|
|
if (!p1)
|
|
|
|
goto fail_length;
|
|
|
|
p = p1;
|
|
|
|
}
|
|
|
|
|
2019-10-09 19:11:20 +01:00
|
|
|
if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED) {
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
2020-01-02 08:32:23 +00:00
|
|
|
(unsigned char *)"application/x-www-form-urlencoded",
|
|
|
|
33, &p, end))
|
2019-10-09 19:11:20 +01:00
|
|
|
goto fail_length;
|
|
|
|
lws_client_http_body_pending(wsi, 1);
|
|
|
|
}
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
/* give userland a chance to append, eg, cookies */
|
|
|
|
|
2021-07-05 16:41:41 +08:00
|
|
|
#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
|
|
|
|
if (wsi->flags & LCCSCF_CACHE_COOKIES)
|
|
|
|
lws_cookie_send_cookies(wsi, (char **)&p, (char *)end);
|
|
|
|
#endif
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (wsi->a.protocol->callback(wsi,
|
2018-03-27 09:17:19 +08:00
|
|
|
LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
|
2020-12-12 06:21:40 +00:00
|
|
|
wsi->user_space, &p, lws_ptr_diff_size_t(end, p) - 12))
|
2018-04-16 19:52:28 +08:00
|
|
|
goto fail_length;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
2018-04-16 19:52:28 +08:00
|
|
|
goto fail_length;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2019-10-02 10:49:18 -07:00
|
|
|
m = LWS_WRITE_HTTP_HEADERS;
|
|
|
|
#if defined(LWS_WITH_CLIENT)
|
|
|
|
/* below is not needed in spec, indeed it destroys the long poll
|
|
|
|
* feature, but required by nghttp2 */
|
2020-01-30 13:19:11 +00:00
|
|
|
if ((wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) &&
|
2021-03-23 07:14:26 +00:00
|
|
|
!(wsi->client_http_body_pending || lws_has_buffered_out(wsi)))
|
2019-10-02 10:49:18 -07:00
|
|
|
m |= LWS_WRITE_H2_STREAM_END;
|
|
|
|
#endif
|
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
// lwsl_hexdump_notice(start, p - start);
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), (enum lws_write_protocol)m);
|
2019-10-02 10:49:18 -07:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
if (n != lws_ptr_diff(p, start)) {
|
2018-03-27 09:17:19 +08:00
|
|
|
lwsl_err("_write returned %d from %ld\n", n,
|
|
|
|
(long)(p - start));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-12-26 02:35:41 +00:00
|
|
|
/*
|
|
|
|
* Normally let's charge up the peer tx credit a bit. But if
|
|
|
|
* MANUAL_REFLOW is set, just set it to the initial credit given in
|
|
|
|
* the client create info
|
|
|
|
*/
|
|
|
|
|
|
|
|
n = 4 * 65536;
|
|
|
|
if (wsi->flags & LCCSCF_H2_MANUAL_RXFLOW) {
|
|
|
|
n = wsi->txc.manual_initial_tx_credit;
|
|
|
|
wsi->txc.manual = 1;
|
|
|
|
}
|
|
|
|
|
2020-04-06 13:22:01 +01:00
|
|
|
if (lws_h2_update_peer_txcredit(wsi, wsi->mux.my_sid, n))
|
2019-12-26 02:35:41 +00:00
|
|
|
return 1;
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
lws_h2_state(wsi, LWS_H2_STATE_OPEN);
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2020-01-02 08:32:23 +00:00
|
|
|
if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME)
|
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
return 0;
|
2018-04-16 19:52:28 +08:00
|
|
|
|
|
|
|
fail_length:
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_err("Client hdrs too long: incr context info.pt_serv_buf_size\n");
|
2018-04-16 19:52:28 +08:00
|
|
|
|
|
|
|
return -1;
|
2018-03-27 09:17:19 +08:00
|
|
|
}
|
2019-10-03 08:31:34 -07:00
|
|
|
#endif
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2020-04-16 06:53:10 +01:00
|
|
|
#if defined(LWS_ROLE_WS) && defined(LWS_WITH_SERVER)
|
2017-11-14 07:35:05 +08:00
|
|
|
int
|
|
|
|
lws_h2_ws_handshake(struct lws *wsi)
|
|
|
|
{
|
2018-10-02 05:42:56 +08:00
|
|
|
uint8_t buf[LWS_PRE + 2048], *p = buf + LWS_PRE, *start = p,
|
2018-03-11 11:26:06 +08:00
|
|
|
*end = &buf[sizeof(buf) - 1];
|
2017-11-14 07:35:05 +08:00
|
|
|
const struct lws_http_mount *hit;
|
|
|
|
const char * uri_ptr;
|
2020-12-12 06:21:40 +00:00
|
|
|
size_t m;
|
|
|
|
int n;
|
2017-11-14 07:35:05 +08:00
|
|
|
|
|
|
|
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) > 64)
|
|
|
|
return -1;
|
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
if (wsi->proxied_ws_parent && wsi->child_list) {
|
|
|
|
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
|
|
|
|
(uint8_t *)lws_hdr_simple_ptr(wsi,
|
|
|
|
WSI_TOKEN_PROTOCOL),
|
2019-10-27 12:55:13 +00:00
|
|
|
(int)strlen(lws_hdr_simple_ptr(wsi,
|
2019-03-19 11:53:57 +08:00
|
|
|
WSI_TOKEN_PROTOCOL)),
|
|
|
|
&p, end))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* we can only return the protocol header if:
|
|
|
|
* - one came in, and ... */
|
|
|
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) &&
|
|
|
|
/* - it is not an empty string */
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.protocol->name && wsi->a.protocol->name[0]) {
|
2020-07-27 10:03:12 +01:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SERVER)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the h2 version of server-ws.c understanding that it
|
|
|
|
* did the ws upgrade on a ss server object, therefore it needs
|
|
|
|
* to pass back to the peer the policy ws-protocol name, not
|
|
|
|
* the generic ss-ws.c protocol name
|
|
|
|
*/
|
|
|
|
|
2020-08-08 07:24:13 +01:00
|
|
|
if (wsi->a.vhost && wsi->a.vhost->ss_handle &&
|
|
|
|
wsi->a.vhost->ss_handle->policy->u.http.u.ws.subprotocol) {
|
2020-07-27 10:03:12 +01:00
|
|
|
lws_ss_handle_t *h =
|
|
|
|
(lws_ss_handle_t *)wsi->a.opaque_user_data;
|
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_notice("%s: Server SS %s .wsi %s switching to ws protocol\n",
|
|
|
|
__func__, lws_ss_tag(h), lws_wsi_tag(h->wsi));
|
2020-07-27 10:03:12 +01:00
|
|
|
|
|
|
|
wsi->a.protocol = &protocol_secstream_ws;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* inform the SS user code that this has done a one-way
|
|
|
|
* upgrade to some other protocol... it will likely
|
|
|
|
* want to treat subsequent payloads differently
|
|
|
|
*/
|
|
|
|
|
|
|
|
lws_ss_event_helper(h, LWSSSCS_SERVER_UPGRADE);
|
|
|
|
|
|
|
|
lws_mux_mark_immortal(wsi);
|
|
|
|
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
|
|
|
|
(unsigned char *)wsi->a.vhost->ss_handle->policy->
|
|
|
|
u.http.u.ws.subprotocol,
|
|
|
|
(int)strlen(wsi->a.vhost->ss_handle->policy->
|
|
|
|
u.http.u.ws.subprotocol), &p, end))
|
|
|
|
return -1;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
|
2019-03-19 11:53:57 +08:00
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
(unsigned char *)wsi->a.protocol->name,
|
|
|
|
(int)strlen(wsi->a.protocol->name), &p, end))
|
2020-07-27 10:03:12 +01:00
|
|
|
return -1;
|
2019-03-19 11:53:57 +08:00
|
|
|
}
|
2017-11-14 07:35:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
|
|
|
return -1;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
m = lws_ptr_diff_size_t(p, start);
|
2019-03-19 11:53:57 +08:00
|
|
|
// lwsl_hexdump_notice(start, m);
|
2018-03-11 11:26:06 +08:00
|
|
|
n = lws_write(wsi, start, m, LWS_WRITE_HTTP_HEADERS);
|
2020-12-12 06:21:40 +00:00
|
|
|
if (n != (int)m) {
|
|
|
|
lwsl_err("_write returned %d from %d\n", n, (int)m);
|
2017-11-14 07:35:05 +08:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* alright clean up, set our state to generic ws established, the
|
|
|
|
* mode / state of the nwsi will get the h2 processing done.
|
|
|
|
*/
|
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
2018-04-25 08:42:18 +08:00
|
|
|
wsi->lws_rx_parse_state = 0; // ==LWS_RXPS_NEW;
|
2017-11-14 07:35:05 +08:00
|
|
|
|
|
|
|
uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH);
|
|
|
|
n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH);
|
|
|
|
hit = lws_find_mount(wsi, uri_ptr, n);
|
|
|
|
|
|
|
|
if (hit && hit->cgienv &&
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO, wsi->user_space,
|
2017-11-14 07:35:05 +08:00
|
|
|
(void *)hit->cgienv, 0))
|
|
|
|
return 1;
|
|
|
|
|
2019-09-18 13:09:32 +01:00
|
|
|
lws_validity_confirmed(wsi);
|
|
|
|
|
2017-11-14 07:35:05 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
2018-04-11 13:39:42 +08:00
|
|
|
|
|
|
|
int
|
|
|
|
lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
|
|
|
|
{
|
|
|
|
unsigned char *oldbuf = buf;
|
|
|
|
|
|
|
|
// lwsl_notice("%s: h2 path: wsistate 0x%x len %d\n", __func__,
|
|
|
|
// wsi->wsistate, (int)len);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* wsi here is always the network connection wsi, not a stream
|
|
|
|
* wsi. Once we unpicked the framing we will find the right
|
|
|
|
* swsi and make it the target of the frame.
|
|
|
|
*
|
|
|
|
* If it's ws over h2, the nwsi will get us here to do the h2
|
|
|
|
* processing, and that will call us back with the swsi +
|
|
|
|
* ESTABLISHED state for the inner payload, handled in a later
|
|
|
|
* case.
|
|
|
|
*/
|
|
|
|
while (len) {
|
2023-11-10 11:13:24 +00:00
|
|
|
lws_filepos_t body_chunk_len = 0;
|
2018-10-10 13:54:43 +08:00
|
|
|
int m;
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
/*
|
|
|
|
* we were accepting input but now we stopped doing so
|
|
|
|
*/
|
|
|
|
if (lws_is_flowcontrolled(wsi)) {
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_rxflow_cache(wsi, buf, 0, (size_t)len);
|
2018-04-11 13:39:42 +08:00
|
|
|
buf += len;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* lws_h2_parser() may send something; when it gets the
|
|
|
|
* whole frame, it will want to perform some action
|
|
|
|
* involving a reply. But we may be in a partial send
|
|
|
|
* situation on the network wsi...
|
|
|
|
*
|
|
|
|
* Even though we may be in a partial send and unable to
|
|
|
|
* send anything new, we still have to parse the network
|
|
|
|
* wsi in order to gain tx credit to send, which is
|
|
|
|
* potentially necessary to clear the old partial send.
|
|
|
|
*
|
|
|
|
* ALL network wsi-specific frames are sent by PPS
|
|
|
|
* already, these are sent as a priority on the writable
|
|
|
|
* handler, and so respect partial sends. The only
|
|
|
|
* problem is when a stream wsi wants to send an, eg,
|
|
|
|
* reply headers frame in response to the parsing
|
|
|
|
* we will do now... the *stream wsi* must stall in a
|
|
|
|
* different state until it is able to do so from a
|
|
|
|
* priority on the WRITABLE callback, same way that
|
|
|
|
* file transfers operate.
|
|
|
|
*/
|
|
|
|
|
|
|
|
m = lws_h2_parser(wsi, buf, len, &body_chunk_len);
|
|
|
|
if (m && m != 2) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_debug("%s: http2_parser bail: %d\n", __func__, m);
|
2018-04-11 13:39:42 +08:00
|
|
|
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
|
|
|
"lws_read_h2 bail");
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (m == 2) {
|
|
|
|
/* swsi has been closed */
|
|
|
|
buf += body_chunk_len;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf += body_chunk_len;
|
|
|
|
len -= body_chunk_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lws_ptr_diff(buf, oldbuf);
|
|
|
|
}
|
|
|
|
|
2019-09-13 10:33:24 +01:00
|
|
|
int
|
|
|
|
lws_h2_client_stream_long_poll_rxonly(struct lws *wsi)
|
|
|
|
{
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (!wsi->mux_substream)
|
2019-09-13 10:33:24 +01:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Elect to send an empty DATA with END_STREAM, to force the stream
|
|
|
|
* into HALF_CLOSED LOCAL
|
|
|
|
*/
|
|
|
|
wsi->h2.long_poll = 1;
|
|
|
|
wsi->h2.send_END_STREAM = 1;
|
|
|
|
|
2020-02-29 12:37:24 +00:00
|
|
|
// lws_header_table_detach(wsi, 0);
|
2019-11-06 21:34:14 +00:00
|
|
|
|
2019-09-13 10:33:24 +01:00
|
|
|
lws_callback_on_writable(wsi);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|