2014-10-08 12:00:53 +08:00
|
|
|
/*
|
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
|
|
*
|
2018-11-23 08:47:56 +08:00
|
|
|
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
|
2014-10-08 12:00:53 +08:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation:
|
|
|
|
* version 2.1 of the License.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
* MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2018-05-03 10:49:36 +08:00
|
|
|
#include "core/private.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
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
static struct lws_h2_protocol_send *
|
|
|
|
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
|
|
|
{
|
2018-04-25 06:53:30 +08:00
|
|
|
wsi->h2.h2n->set = wsi->vhost->h2.set;
|
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;
|
|
|
|
lwsl_info("%s: wsi %p: state %s -> %s\n", __func__, 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
|
|
|
}
|
|
|
|
|
2015-12-04 11:08:32 +08:00
|
|
|
struct lws *
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
|
2015-12-06 10:05:37 +08:00
|
|
|
unsigned int sid)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws *wsi;
|
|
|
|
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;
|
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) {
|
2018-03-27 09:17:19 +08:00
|
|
|
lwsl_info("%s: tried to open lower sid %d\n", __func__, sid);
|
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 */
|
2017-12-01 11:09:32 +08:00
|
|
|
if (parent_wsi->h2.child_count + 1 >
|
|
|
|
parent_wsi->h2.h2n->set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_notice("reached concurrent stream limit\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-04-27 12:49:42 +08:00
|
|
|
wsi = lws_create_new_server_wsi(vh, parent_wsi->tsi);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!wsi) {
|
|
|
|
lwsl_notice("new server wsi failed (vh %p)\n", vh);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
h2n->highest_sid_opened = sid;
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.my_sid = sid;
|
2017-10-13 10:33:02 +08:00
|
|
|
wsi->http2_substream = 1;
|
2017-11-10 08:56:44 +08:00
|
|
|
wsi->seen_nonpseudoheader = 0;
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.parent_wsi = parent_wsi;
|
2018-04-11 13:39:42 +08:00
|
|
|
wsi->role_ops = parent_wsi->role_ops;
|
2017-10-13 10:33:02 +08:00
|
|
|
/* new guy's sibling is whoever was the first child before */
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.sibling_list = parent_wsi->h2.child_list;
|
2017-10-13 10:33:02 +08:00
|
|
|
/* first child is now the new guy */
|
2017-12-01 11:09:32 +08:00
|
|
|
parent_wsi->h2.child_list = wsi;
|
|
|
|
parent_wsi->h2.child_count++;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.my_priority = 16;
|
|
|
|
wsi->h2.tx_cr = nwsi->h2.h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
|
2018-11-23 08:47:56 +08:00
|
|
|
wsi->h2.peer_tx_cr_est =
|
|
|
|
nwsi->vhost->h2.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
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
wsi->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;
|
|
|
|
|
|
|
|
wsi->vhost->conn_stats.h2_subs++;
|
2014-10-08 12:00:53 +08:00
|
|
|
|
2017-10-16 12:52:32 +08:00
|
|
|
lwsl_info("%s: %p new ch %p, sid %d, usersp=%p, tx cr %d, "
|
|
|
|
"peer_credit %d (nwsi tx_cr %d)\n",
|
2017-10-13 10:33:02 +08:00
|
|
|
__func__, parent_wsi, wsi, sid, wsi->user_space,
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.tx_cr, wsi->h2.peer_tx_cr_est, nwsi->h2.tx_cr);
|
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 */
|
2017-12-01 11:09:32 +08:00
|
|
|
parent_wsi->h2.child_list = wsi->h2.sibling_list;
|
|
|
|
parent_wsi->h2.child_count--;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-09-04 08:06:46 +08:00
|
|
|
vh->context->count_wsi_allocated--;
|
|
|
|
|
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);
|
vhost_destroy: use vhost wsi reference counting to trigger destroy
This changes the vhost destroy flow to only hand off the listen
socket if another vhost sharing it, and mark the vhost as
being_destroyed.
Each tsi calls lws_check_deferred_free() once a second, if it sees
any vhost being_destroyed there, it closes all wsi on its tsi on
the same vhost, one time.
As the wsi on the vhost complete close (ie, after libuv async close
if on libuv event loop), they decrement a reference count for all
wsi open on the vhost. The tsi who closes the last one then
completes the destroy flow for the vhost itself... it's random
which tsi completes the vhost destroy but since there are no
wsi left on the vhost, and it holds the context lock, nothing
can conflict.
The advantage of this is that owning tsi do the close for wsi
that are bound to the vhost under destruction, at a time when
they are guaranteed to be idle for service, and they do it with
both vhost and context locks owned, so no other service thread
can conflict for stuff protected by those either.
For the situation the user code may have allocations attached to
the vhost, this adds args to lws_vhost_destroy() to allow destroying
the user allocations just before the vhost is freed.
2018-06-16 09:31:07 +08:00
|
|
|
lws_vhost_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 */
|
|
|
|
if (parent_wsi->h2.child_count + 1 >
|
|
|
|
parent_wsi->h2.h2n->set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
|
|
|
|
lwsl_notice("reached concurrent stream limit\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sid is set just before issuing the headers, ensuring monoticity */
|
|
|
|
|
|
|
|
wsi->seen_nonpseudoheader = 0;
|
2018-11-12 15:24:42 +08:00
|
|
|
#if !defined(LWS_NO_CLIENT)
|
2018-03-27 09:17:19 +08:00
|
|
|
wsi->client_h2_substream = 1;
|
2018-11-12 15:24:42 +08:00
|
|
|
#endif
|
2018-03-27 09:17:19 +08:00
|
|
|
wsi->h2.initialized = 1;
|
|
|
|
|
|
|
|
wsi->h2.parent_wsi = parent_wsi;
|
|
|
|
/* new guy's sibling is whoever was the first child before */
|
|
|
|
wsi->h2.sibling_list = parent_wsi->h2.child_list;
|
|
|
|
/* first child is now the new guy */
|
|
|
|
parent_wsi->h2.child_list = wsi;
|
|
|
|
parent_wsi->h2.child_count++;
|
|
|
|
|
|
|
|
wsi->h2.my_priority = 16;
|
|
|
|
wsi->h2.tx_cr = nwsi->h2.h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
|
2018-11-23 08:47:56 +08:00
|
|
|
wsi->h2.peer_tx_cr_est =
|
|
|
|
nwsi->vhost->h2.set.s[H2SET_INITIAL_WINDOW_SIZE];
|
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);
|
|
|
|
|
|
|
|
wsi->vhost->conn_stats.h2_subs++;
|
|
|
|
|
|
|
|
return wsi;
|
|
|
|
|
|
|
|
bail1:
|
|
|
|
/* undo the insert */
|
|
|
|
parent_wsi->h2.child_list = wsi->h2.sibling_list;
|
|
|
|
parent_wsi->h2.child_count--;
|
|
|
|
|
|
|
|
if (wsi->user_space)
|
|
|
|
lws_free_set_NULL(wsi->user_space);
|
|
|
|
wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
|
|
|
|
lws_free(wsi);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int lws_h2_issue_preface(struct lws *wsi)
|
|
|
|
{
|
|
|
|
struct lws_h2_netconn *h2n = wsi->h2.h2n;
|
|
|
|
struct lws_h2_protocol_send *pps;
|
|
|
|
|
|
|
|
if (lws_issue_raw(wsi, (uint8_t *)preface, strlen(preface)) !=
|
|
|
|
(int)strlen(preface))
|
|
|
|
return 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;
|
|
|
|
wsi->h2.tx_cr = 65535;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
struct lws *
|
|
|
|
lws_h2_wsi_from_id(struct lws *parent_wsi, unsigned int sid)
|
|
|
|
{
|
2017-12-01 11:09:32 +08:00
|
|
|
lws_start_foreach_ll(struct lws *, wsi, parent_wsi->h2.child_list) {
|
|
|
|
if (wsi->h2.my_sid == sid)
|
2017-10-13 10:33:02 +08:00
|
|
|
return wsi;
|
2017-12-01 11:09:32 +08:00
|
|
|
} lws_end_foreach_ll(wsi, h2.sibling_list);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-12-04 11:08:32 +08:00
|
|
|
int lws_remove_server_child_wsi(struct lws_context *context, struct lws *wsi)
|
2014-10-08 12:00:53 +08:00
|
|
|
{
|
2017-12-01 11:09:32 +08:00
|
|
|
lws_start_foreach_llp(struct lws **, w, wsi->h2.child_list) {
|
2014-10-08 12:00:53 +08:00
|
|
|
if (*w == wsi) {
|
2017-12-01 11:09:32 +08:00
|
|
|
*w = wsi->h2.sibling_list;
|
|
|
|
(wsi->h2.parent_wsi)->h2.child_count--;
|
2014-10-08 12:00:53 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2017-12-01 11:09:32 +08:00
|
|
|
} lws_end_foreach_llp(w, h2.sibling_list);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
lwsl_err("%s: can't find %p\n", __func__, wsi);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
lwsl_info("%s: %p: ERR 0x%x, '%s'\n", __func__, wsi, err, reason);
|
|
|
|
|
|
|
|
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:24:55 +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;
|
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
lwsl_info("%s: RST_STREAM 0x%x, sid %d, REASON '%s'\n", __func__, err,
|
|
|
|
wsi->h2.my_sid, reason);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
pps->u.rs.sid = wsi->h2.my_sid;
|
2017-10-13 10:33:02 +08:00
|
|
|
pps->u.rs.err = err;
|
2019-11-04 21:24:55 +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,
|
|
|
|
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) {
|
2014-10-08 12:00:53 +08:00
|
|
|
a = (buf[0] << 8) | buf[1];
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!a || a >= H2SET_COUNT)
|
|
|
|
goto skip;
|
|
|
|
b = buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5];
|
|
|
|
|
|
|
|
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-07-13 14:50:58 -07:00
|
|
|
#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
|
2019-06-05 05:04:17 +01:00
|
|
|
//FIXME: Workaround for FIRMWARE-4632 until cloud-side issue is fixed.
|
|
|
|
if (b == 0x7fffffff) {
|
|
|
|
b = 65535;
|
|
|
|
lwsl_info("init window size 0x7fffffff\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//FIXME: end of FIRMWARE-4632 workaround
|
|
|
|
#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,
|
2017-12-01 11:09:32 +08:00
|
|
|
nwsi->h2.child_list) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("%s: adi child tc cr %d +%d -> %d",
|
|
|
|
__func__,
|
2017-12-01 11:09:32 +08:00
|
|
|
w->h2.tx_cr, b - settings->s[a],
|
|
|
|
w->h2.tx_cr + b - settings->s[a]);
|
|
|
|
w->h2.tx_cr += b - settings->s[a];
|
|
|
|
if (w->h2.tx_cr > 0 &&
|
2018-11-23 08:47:56 +08:00
|
|
|
w->h2.tx_cr <=
|
|
|
|
(int32_t)(b - settings->s[a]))
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_callback_on_writable(w);
|
2017-12-01 11:09:32 +08:00
|
|
|
} lws_end_foreach_ll(w, h2.sibling_list);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
case H2SET_MAX_FRAME_SIZE:
|
2018-04-25 06:53:30 +08:00
|
|
|
if (b < wsi->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
|
|
|
{
|
2017-12-01 11:09:32 +08:00
|
|
|
int c = wsi->h2.tx_cr;
|
2017-10-13 10:33:02 +08:00
|
|
|
struct lws *nwsi;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!wsi->http2_substream && !wsi->upgraded_to_http2)
|
|
|
|
return ~0x80000000;
|
|
|
|
|
|
|
|
nwsi = lws_get_network_wsi(wsi);
|
|
|
|
|
|
|
|
lwsl_info ("%s: %p: own tx credit %d: nwsi credit %d\n",
|
2017-12-01 11:09:32 +08:00
|
|
|
__func__, wsi, c, nwsi->h2.tx_cr);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (nwsi->h2.tx_cr < c)
|
|
|
|
c = nwsi->h2.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);
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.tx_cr -= consumed;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (nwsi != wsi)
|
2017-12-01 11:09:32 +08:00
|
|
|
nwsi->h2.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);
|
|
|
|
|
2014-10-08 12:00:53 +08:00
|
|
|
*p++ = len >> 16;
|
|
|
|
*p++ = len >> 8;
|
|
|
|
*p++ = len;
|
|
|
|
*p++ = type;
|
|
|
|
*p++ = flags;
|
|
|
|
*p++ = sid >> 24;
|
|
|
|
*p++ = sid >> 16;
|
|
|
|
*p++ = sid >> 8;
|
|
|
|
*p++ = sid;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_debug("%s: %p (eff %p). typ %d, fl 0x%x, sid=%d, len=%d, "
|
2018-11-23 08:47:56 +08:00
|
|
|
"txcr=%d, nwsi->txcr=%d\n", __func__, wsi, nwsi, type, flags,
|
|
|
|
sid, len, wsi->h2.tx_cr, nwsi->h2.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) {
|
2017-12-01 11:09:32 +08:00
|
|
|
if (wsi->h2.tx_cr < (int)len)
|
2015-12-06 10:05:37 +08:00
|
|
|
lwsl_err("%s: %p: sending payload len %d"
|
2017-10-13 10:33:02 +08:00
|
|
|
" but tx_cr only %d!\n", __func__, wsi,
|
2017-12-01 11:09:32 +08:00
|
|
|
len, wsi->h2.tx_cr);
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_tx_cr_consume(wsi, 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
|
|
|
{
|
|
|
|
*buf++ = n >> 8;
|
|
|
|
*buf++ = n;
|
2017-12-01 11:09:32 +08:00
|
|
|
*buf++ = wsi->h2.h2n->set.s[n] >> 24;
|
|
|
|
*buf++ = wsi->h2.h2n->set.s[n] >> 16;
|
|
|
|
*buf++ = wsi->h2.h2n->set.s[n] >> 8;
|
|
|
|
*buf = wsi->h2.h2n->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;
|
|
|
|
|
|
|
|
lwsl_info("%s: %p: %d\n", __func__, wsi, pps->type);
|
|
|
|
|
|
|
|
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++)
|
|
|
|
if (h2n->set.s[n] != lws_h2_defaults.s[n]) {
|
|
|
|
lwsl_debug("sending SETTING %d 0x%x\n", n,
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.h2n->set.s[n]);
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_set_bin(wsi, n, &set[LWS_PRE + m]);
|
|
|
|
m += sizeof(h2n->one_setting);
|
|
|
|
}
|
|
|
|
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,
|
2018-03-27 09:17:19 +08:00
|
|
|
flags, LWS_H2_STREAM_ID_MASTER, 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;
|
|
|
|
|
|
|
|
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) {
|
|
|
|
lwsl_err("ack tells %d\n", n);
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
/* 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);
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->http.fop_fd = NULL;
|
2017-10-13 10:33:02 +08:00
|
|
|
if (lws_is_ssl(lws_get_network_wsi(wsi)))
|
|
|
|
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
|
|
|
*/
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->swsi = lws_wsi_server_new(wsi->vhost, wsi, 1);
|
|
|
|
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);
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->h2.tx_cr =
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
|
|
|
|
lwsl_info("initial tx credit on conn %p: %d\n",
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi, h2n->swsi->h2.tx_cr);
|
|
|
|
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");
|
|
|
|
|
|
|
|
wsi->vhost->conn_stats.h2_trans++;
|
|
|
|
|
|
|
|
if (lws_http_action(h2n->swsi))
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LWS_H2_PPS_PONG:
|
|
|
|
lwsl_debug("sending PONG\n");
|
|
|
|
memcpy(&set[LWS_PRE], pps->u.ping.ping_payload, 8);
|
|
|
|
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING,
|
|
|
|
LWS_H2_FLAG_SETTINGS_ACK,
|
|
|
|
LWS_H2_STREAM_ID_MASTER, 8,
|
|
|
|
&set[LWS_PRE]);
|
|
|
|
if (n != 8) {
|
|
|
|
lwsl_info("send %d %d\n", n, m);
|
|
|
|
goto bail;
|
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");
|
|
|
|
*p++ = pps->u.ga.highest_sid >> 24;
|
|
|
|
*p++ = pps->u.ga.highest_sid >> 16;
|
|
|
|
*p++ = pps->u.ga.highest_sid >> 8;
|
|
|
|
*p++ = pps->u.ga.highest_sid;
|
|
|
|
*p++ = pps->u.ga.err >> 24;
|
|
|
|
*p++ = pps->u.ga.err >> 16;
|
|
|
|
*p++ = pps->u.ga.err >> 8;
|
|
|
|
*p++ = 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,
|
2017-10-25 08:00:23 +08:00
|
|
|
lws_ptr_diff(p, &set[LWS_PRE]),
|
|
|
|
&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");
|
|
|
|
*p++ = pps->u.rs.err >> 24;
|
|
|
|
*p++ = pps->u.rs.err >> 16;
|
|
|
|
*p++ = pps->u.rs.err >> 8;
|
|
|
|
*p++ = pps->u.rs.err;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
cwsi = lws_h2_wsi_from_id(wsi, pps->u.rs.sid);
|
2018-04-17 11:43:20 +08:00
|
|
|
if (cwsi) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_debug("%s: closing cwsi %p %s %s (wsi %p)\n",
|
|
|
|
__func__, cwsi, cwsi->role_ops->name,
|
|
|
|
cwsi->protocol->name, 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:
|
2018-03-11 11:26:06 +08:00
|
|
|
lwsl_debug("Issuing LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n",
|
2017-10-16 12:52:32 +08:00
|
|
|
pps->u.update_window.sid,
|
|
|
|
pps->u.update_window.credit);
|
2017-10-13 10:33:02 +08:00
|
|
|
*p++ = pps->u.update_window.credit >> 24;
|
|
|
|
*p++ = pps->u.update_window.credit >> 16;
|
|
|
|
*p++ = pps->u.update_window.credit >> 8;
|
|
|
|
*p++ = pps->u.update_window.credit;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)) {
|
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "Even Stream ID");
|
|
|
|
|
|
|
|
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-07-13 14:50:58 -07:00
|
|
|
#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
|
2019-06-05 05:04:17 +01:00
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, wsi->vhost->keepalive_timeout);
|
|
|
|
#else
|
2018-03-11 11:26:06 +08:00
|
|
|
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (h2n->sid)
|
|
|
|
h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid);
|
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_debug("%p (%p): fr hdr: typ 0x%x, fla 0x%x, sid 0x%x, len 0x%x\n",
|
2017-10-13 10:33:02 +08:00
|
|
|
wsi, h2n->swsi, h2n->type, h2n->flags, h2n->sid,
|
|
|
|
h2n->length);
|
|
|
|
|
|
|
|
if (h2n->we_told_goaway && h2n->sid > h2n->highest_sid)
|
|
|
|
h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
|
|
|
|
|
|
|
|
if (h2n->type == LWS_H2_FRAME_TYPE_COUNT)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (h2n->length > h2n->set.s[H2SET_MAX_FRAME_SIZE]) {
|
|
|
|
/*
|
|
|
|
* peer sent us something bigger than we told
|
|
|
|
* it we would allow
|
|
|
|
*/
|
2018-04-26 15:27:02 +08:00
|
|
|
lwsl_info("received oversize frame %d\n", 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)
|
|
|
|
lwsl_info("%s: wsi %p, State: %s, received cmd %d\n",
|
|
|
|
__func__, 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
|
|
|
|
#if !defined(LWS_NO_CLIENT)
|
|
|
|
&& wsi->client_h2_alpn
|
|
|
|
#endif
|
|
|
|
) {
|
2018-03-11 11:26:06 +08:00
|
|
|
lwsl_notice("ignoring straggling data\n");
|
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 {
|
|
|
|
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;
|
|
|
|
}
|
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 */
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("%s: wsi %p, No child for sid %d, rxcmd %d\n",
|
2017-10-13 10:33:02 +08:00
|
|
|
__func__, h2n->swsi, h2n->sid, h2n->type);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (h2n->swsi && h2n->sid &&
|
2017-12-01 11:09:32 +08:00
|
|
|
!(http2_rx_validity[h2n->swsi->h2.h2_state] & (1 << h2n->type))) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("%s: wsi %p, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\n",
|
|
|
|
__func__, 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;
|
|
|
|
lws_h2_goaway(wsi, n, "invalid rx for state");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (h2n->cont_exp && (h2n->cont_exp_sid != h2n->sid ||
|
|
|
|
h2n->type != LWS_H2_FRAME_TYPE_CONTINUATION)) {
|
|
|
|
lwsl_info("%s: expected cont on sid %d (got %d on sid %d)\n",
|
|
|
|
__func__, h2n->cont_exp_sid, h2n->type, h2n->sid);
|
|
|
|
h2n->cont_exp = 0;
|
|
|
|
if (h2n->cont_exp_headers)
|
|
|
|
n = H2_ERR_COMPRESSION_ERROR;
|
|
|
|
else
|
|
|
|
n = H2_ERR_PROTOCOL_ERROR;
|
|
|
|
lws_h2_goaway(wsi, n, "Continuation hdrs State");
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
lwsl_info("Frame header DATA: sid %d\n", h2n->sid);
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
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)) {
|
|
|
|
if ((!h2n->length) || h2n->length % 6) {
|
|
|
|
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
|
|
|
|
|
|
|
if (wsi->upgraded_to_http2) {
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
}
|
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:
|
|
|
|
lwsl_info("LWS_H2_FRAME_TYPE_CONTINUATION: sid = %d\n",
|
|
|
|
h2n->sid);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
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:
|
|
|
|
lwsl_info("HEADERS: frame header: sid = %d\n", h2n->sid);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
#if !defined(LWS_NO_CLIENT)
|
|
|
|
if (wsi->client_h2_alpn) {
|
|
|
|
if (h2n->sid) {
|
|
|
|
h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid);
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("HEADERS: nwsi %p: sid %d mapped "
|
|
|
|
"to wsi %p\n", wsi, h2n->sid,
|
|
|
|
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 */
|
2017-12-01 11:09:32 +08:00
|
|
|
if (wsi->h2.child_count + 1 >
|
|
|
|
wsi->h2.h2n->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
|
|
|
|
2017-10-16 12:52:32 +08:00
|
|
|
h2n->swsi = lws_wsi_server_new(wsi->vhost, wsi,
|
|
|
|
h2n->sid);
|
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
|
|
|
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
|
|
|
|
if (!pps)
|
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;
|
2018-02-05 10:54:18 +08:00
|
|
|
pps->u.update_window.sid = h2n->sid;
|
|
|
|
pps->u.update_window.credit = 4 * 65536;
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->swsi->h2.peer_tx_cr_est +=
|
|
|
|
pps->u.update_window.credit;
|
2018-02-05 10:54:18 +08:00
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
|
|
|
|
if (!pps)
|
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;
|
2018-02-05 10:54:18 +08:00
|
|
|
pps->u.update_window.sid = 0;
|
|
|
|
pps->u.update_window.credit = 4 * 65536;
|
|
|
|
wsi->h2.peer_tx_cr_est += pps->u.update_window.credit;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
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.
|
|
|
|
*/
|
2017-12-01 11:09:32 +08:00
|
|
|
lws_start_foreach_ll(struct lws *, w, wsi->h2.child_list) {
|
|
|
|
if (w->h2.my_sid < h2n->sid &&
|
|
|
|
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");
|
2018-04-11 13:39:42 +08:00
|
|
|
assert(w->h2.sibling_list != w);
|
2017-12-01 11:09:32 +08:00
|
|
|
} lws_end_foreach_ll(w, h2.sibling_list);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* END_STREAM means after servicing this, close the stream */
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->h2.END_STREAM =
|
2017-10-16 12:52:32 +08:00
|
|
|
!!(h2n->flags & LWS_H2_FLAG_END_STREAM);
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("%s: hdr END_STREAM = %d\n",__func__,
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->h2.END_STREAM);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
h2n->cont_exp = !(h2n->flags & LWS_H2_FLAG_END_HEADERS);
|
|
|
|
h2n->cont_exp_sid = h2n->sid;
|
|
|
|
h2n->cont_exp_headers = 1;
|
2018-04-26 15:27:02 +08:00
|
|
|
// lws_header_table_reset(h2n->swsi, 0);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
update_end_headers:
|
|
|
|
/* 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);
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("%p: END_HEADERS %d\n", h2n->swsi,
|
|
|
|
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:
|
|
|
|
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[] = {
|
|
|
|
"GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", "CONNECT", "HEAD"
|
|
|
|
};
|
|
|
|
static unsigned char method_index[] = {
|
|
|
|
WSI_TOKEN_GET_URI,
|
|
|
|
WSI_TOKEN_POST_URI,
|
|
|
|
WSI_TOKEN_OPTIONS_URI,
|
|
|
|
WSI_TOKEN_PUT_URI,
|
|
|
|
WSI_TOKEN_PATCH_URI,
|
|
|
|
WSI_TOKEN_DELETE_URI,
|
|
|
|
WSI_TOKEN_CONNECT,
|
|
|
|
WSI_TOKEN_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)
|
|
|
|
h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid);
|
|
|
|
|
|
|
|
if (h2n->sid > h2n->highest_sid)
|
|
|
|
h2n->highest_sid = h2n->sid;
|
|
|
|
|
|
|
|
/* set our initial window size */
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!wsi->h2.initialized) {
|
|
|
|
wsi->h2.tx_cr = h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("initial tx credit on master %p: %d\n", wsi,
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.tx_cr);
|
|
|
|
wsi->h2.initialized = 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
#if !defined(LWS_NO_CLIENT)
|
|
|
|
if (wsi->client_h2_alpn &&
|
|
|
|
!(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 */
|
|
|
|
|
|
|
|
wsi->http.fop_fd = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we need to treat the headers from the upgrade as the
|
|
|
|
* first job. So these need to get shifted to sid 1.
|
|
|
|
*/
|
|
|
|
h2n->swsi = lws_wsi_server_new(wsi->vhost, wsi, 1);
|
|
|
|
if (!h2n->swsi)
|
|
|
|
return 1;
|
|
|
|
h2n->sid = 1;
|
|
|
|
|
|
|
|
assert(lws_h2_wsi_from_id(wsi, 1) == h2n->swsi);
|
|
|
|
|
2018-04-11 13:39:42 +08: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;
|
2018-03-27 09:17:19 +08:00
|
|
|
h2n->swsi->client_h2_substream = 1;
|
|
|
|
|
|
|
|
h2n->swsi->protocol = wsi->protocol;
|
2019-08-08 21:15:57 +01:00
|
|
|
if (h2n->swsi->user_space && !h2n->swsi->user_space_externally_allocated)
|
|
|
|
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;
|
2018-12-01 06:35:20 +08:00
|
|
|
h2n->swsi->opaque_user_data = wsi->opaque_user_data;
|
|
|
|
wsi->opaque_user_data = NULL;
|
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
|
|
|
|
|
|
|
lwsl_info("%s: MIGRATING nwsi %p: swsi %p\n", __func__,
|
|
|
|
wsi, h2n->swsi);
|
|
|
|
h2n->swsi->h2.tx_cr =
|
|
|
|
h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
|
|
|
|
lwsl_info("initial tx credit on conn %p: %d\n",
|
|
|
|
h2n->swsi, h2n->swsi->h2.tx_cr);
|
|
|
|
h2n->swsi->h2.initialized = 1;
|
|
|
|
|
|
|
|
lws_callback_on_writable(h2n->swsi);
|
|
|
|
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
lwsl_info("%s: scheduled settings ack PPS\n", __func__);
|
|
|
|
|
|
|
|
/* also attach any queued guys */
|
|
|
|
|
|
|
|
/* we have a transaction queue that wants to pipeline */
|
|
|
|
lws_vhost_lock(wsi->vhost);
|
2019-03-20 07:39:55 +08:00
|
|
|
lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
|
|
|
|
wsi->dll2_cli_txn_queue_owner.head) {
|
2018-03-27 09:17:19 +08:00
|
|
|
struct lws *w = lws_container_of(d, struct lws,
|
2019-03-20 07:39:55 +08:00
|
|
|
dll2_cli_txn_queue);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
if (lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("%s: cli pipeq %p to be h2\n",
|
2018-03-27 09:17:19 +08:00
|
|
|
__func__, w);
|
2018-11-23 08:47:56 +08:00
|
|
|
/* remove ourselves from client queue */
|
2019-03-20 07:39:55 +08:00
|
|
|
lws_dll2_remove(&w->dll2_cli_txn_queue);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
/* attach ourselves as an h2 stream */
|
|
|
|
lws_wsi_h2_adopt(wsi, w);
|
|
|
|
}
|
|
|
|
} lws_end_foreach_dll_safe(d, d1);
|
|
|
|
lws_vhost_unlock(wsi->vhost);
|
|
|
|
}
|
|
|
|
#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");
|
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 */
|
|
|
|
lwsl_info("hpack incomplete %d (type %d, len %d)\n",
|
|
|
|
h2n->hpack, h2n->type, h2n->hpack_len);
|
|
|
|
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
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("http req, wsi=%p, h2n->swsi=%p\n", wsi, h2n->swsi);
|
|
|
|
h2n->swsi->hdr_parsing_completed = 1;
|
|
|
|
|
2018-11-12 15:24:42 +08:00
|
|
|
#if !defined(LWS_NO_CLIENT)
|
2018-03-27 09:17:19 +08:00
|
|
|
if (h2n->swsi->client_h2_substream) {
|
|
|
|
if (lws_client_interpret_server_handshake(h2n->swsi)) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_h2_rst_stream(h2n->swsi,
|
|
|
|
H2_ERR_STREAM_CLOSED,
|
|
|
|
"protocol CLI_EST closed it");
|
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_extant(h2n->swsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->http.rx_content_length = atoll(
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_hdr_simple_ptr(h2n->swsi,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_LENGTH));
|
2017-12-01 11:09:32 +08:00
|
|
|
h2n->swsi->http.rx_content_remain =
|
|
|
|
h2n->swsi->http.rx_content_length;
|
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 {
|
|
|
|
c = lws_token_to_string(n);
|
|
|
|
if (!c) {
|
|
|
|
n++;
|
|
|
|
continue;
|
|
|
|
}
|
2014-10-17 08:38:44 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
len = lws_hdr_total_length(h2n->swsi, 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,
|
|
|
|
n) < 0) {
|
|
|
|
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) {
|
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)
|
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
|
|
|
|
2018-11-12 15:24:42 +08:00
|
|
|
#if !defined(LWS_NO_CLIENT)
|
2018-03-27 09:17:19 +08:00
|
|
|
if (h2n->swsi->client_h2_substream) {
|
|
|
|
lwsl_info("%s: headers: client path\n", __func__);
|
|
|
|
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
|
|
|
|
2018-04-26 15:27:02 +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 ||
|
|
|
|
strncmp(lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_TE),
|
|
|
|
"trailers", n)) {
|
|
|
|
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
|
|
|
|
|
2018-04-17 11:43:20 +08:00
|
|
|
wsi->vhost->conn_stats.h2_trans++;
|
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++)
|
|
|
|
if (!strcasecmp(p, method_names[n])) {
|
|
|
|
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
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_debug("%s: setting DEF_ACT from 0x%x\n", __func__,
|
|
|
|
h2n->swsi->wsistate);
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(h2n->swsi, LRS_DEFERRING_ACTION);
|
2017-12-07 07:20:47 +08:00
|
|
|
lws_callback_on_writable(h2n->swsi);
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_DATA:
|
|
|
|
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
|
|
|
|
2018-11-12 15:24:42 +08:00
|
|
|
#if !defined(LWS_NO_CLIENT)
|
2018-04-05 20:48:08 +08:00
|
|
|
/*
|
|
|
|
* client... remote END_STREAM implies we weren't going to
|
|
|
|
* send anything else anyway.
|
|
|
|
*/
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
if (h2n->swsi->client_h2_substream &&
|
|
|
|
h2n->flags & LWS_H2_FLAG_END_STREAM) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("%s: %p: DATA: end stream\n",
|
|
|
|
__func__, 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:
|
|
|
|
if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK) { // ack
|
|
|
|
} 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:
|
2018-11-03 14:47:48 +08:00
|
|
|
h2n->hpack_e_dep &= ~(1u << 31);
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("WINDOW_UPDATE: sid %d %u (0x%x)\n", h2n->sid,
|
|
|
|
h2n->hpack_e_dep, h2n->hpack_e_dep);
|
|
|
|
|
|
|
|
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
|
|
|
|
2019-07-08 08:48:58 +01:00
|
|
|
if (eff_wsi->vhost->options &
|
|
|
|
LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW &&
|
|
|
|
(uint64_t)eff_wsi->h2.tx_cr + (uint64_t)h2n->hpack_e_dep >
|
|
|
|
(uint64_t)0x7fffffff)
|
|
|
|
h2n->hpack_e_dep = 0x7fffffff - eff_wsi->h2.tx_cr;
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if ((uint64_t)eff_wsi->h2.tx_cr + (uint64_t)h2n->hpack_e_dep >
|
2017-10-13 10:33:02 +08:00
|
|
|
(uint64_t)0x7fffffff) {
|
|
|
|
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;
|
|
|
|
}
|
2017-12-01 11:09:32 +08:00
|
|
|
n = eff_wsi->h2.tx_cr;
|
|
|
|
eff_wsi->h2.tx_cr += h2n->hpack_e_dep;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (n <= 0 && eff_wsi->h2.tx_cr <= 0)
|
2017-10-13 10:33:02 +08:00
|
|
|
/* it helps, but won't change sendability for anyone */
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It did change sendability... for us and any children waiting
|
|
|
|
* on us... reassess blockage for all children first
|
|
|
|
*/
|
2017-12-01 11:09:32 +08:00
|
|
|
lws_start_foreach_ll(struct lws *, w, wsi->h2.child_list) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_callback_on_writable(w);
|
2017-12-01 11:09:32 +08:00
|
|
|
} lws_end_foreach_ll(w, h2.sibling_list);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (eff_wsi->h2.skint && lws_h2_tx_cr_get(eff_wsi)) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_info("%s: %p: skint\n", __func__, wsi);
|
2017-12-01 11:09:32 +08:00
|
|
|
eff_wsi->h2.skint = 0;
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_callback_on_writable(eff_wsi);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_H2_FRAME_TYPE_GOAWAY:
|
|
|
|
lwsl_info("GOAWAY: last sid %d, error 0x%08X, string '%s'\n",
|
2017-10-16 12:52:32 +08:00
|
|
|
h2n->goaway_last_sid, h2n->goaway_err,
|
|
|
|
h2n->goaway_str);
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.GOING_AWAY = 1;
|
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:
|
|
|
|
lwsl_info("LWS_H2_FRAME_TYPE_RST_STREAM: sid %d: reason 0x%x\n",
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->sid, 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
|
2017-11-25 10:10:33 +08:00
|
|
|
lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
|
|
|
|
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;
|
2017-11-25 10:10:33 +08:00
|
|
|
unsigned char c, *oldin = in;
|
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;
|
|
|
|
|
|
|
|
while (inlen--) {
|
|
|
|
|
|
|
|
c = *in++;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
// lwsl_notice("%s: 0x%x\n", __func__, c);
|
|
|
|
|
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
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
lwsl_info("http2: %p: established\n", wsi);
|
2018-04-02 11:55:17 +08:00
|
|
|
lwsi_set_state(wsi, LRS_H2_AWAIT_SETTINGS);
|
2018-02-19 05:31:14 +08:00
|
|
|
h2n->count = 0;
|
|
|
|
wsi->h2.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:
|
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++;
|
|
|
|
|
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",
|
|
|
|
h2n->dep, h2n->weight_temp);
|
|
|
|
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) {
|
2018-11-23 08:47:56 +08: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:
|
|
|
|
n = (h2n->count - 1 - h2n->preamble) %
|
|
|
|
LWS_H2_SETTINGS_LEN;
|
|
|
|
h2n->one_setting[n] = c;
|
|
|
|
if (n != LWS_H2_SETTINGS_LEN - 1)
|
|
|
|
break;
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_h2_settings(wsi, &h2n->set,
|
|
|
|
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[
|
|
|
|
h2n->inside - 9] = c;
|
|
|
|
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
|
|
|
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("%s: LWS_H2_FRAME_TYPE_DATA\n",
|
|
|
|
__func__);
|
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,
|
|
|
|
PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
|
2019-07-13 14:50:58 -07:00
|
|
|
#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
|
2019-06-05 05:04:17 +01:00
|
|
|
wsi->vhost->keepalive_timeout);
|
|
|
|
#else
|
2018-11-23 08:47:56 +08:00
|
|
|
31);
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
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);
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_info("%s: swsi %p to LRS_BODY\n",
|
2018-04-02 11:55:17 +08:00
|
|
|
__func__, h2n->swsi);
|
2018-02-19 05:31:14 +08:00
|
|
|
}
|
2017-11-25 10:10:33 +08:00
|
|
|
|
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 <
|
|
|
|
inlen + 1 && /* last */
|
|
|
|
h2n->inside < h2n->length) {
|
|
|
|
/* 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
|
|
|
|
2018-03-02 14:22:49 +08:00
|
|
|
n = (int)inlen + 1;
|
2018-02-19 05:31:14 +08:00
|
|
|
if (n > (int)(h2n->length - h2n->count + 1)) {
|
|
|
|
n = h2n->length - h2n->count + 1;
|
|
|
|
lwsl_debug("---- restricting len to %d vs %ld\n", n, (long)inlen + 1);
|
|
|
|
}
|
2018-11-12 15:24:42 +08:00
|
|
|
#if !defined(LWS_NO_CLIENT)
|
2018-03-27 09:17:19 +08:00
|
|
|
if (h2n->swsi->client_h2_substream) {
|
|
|
|
|
|
|
|
m = user_callback_handle_rxflow(
|
2018-11-23 08:47:56 +08:00
|
|
|
h2n->swsi->protocol->callback,
|
|
|
|
h2n->swsi,
|
|
|
|
LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
|
|
|
|
h2n->swsi->user_space,
|
|
|
|
in - 1, n);
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
in += n - 1;
|
|
|
|
h2n->inside += n;
|
|
|
|
h2n->count += n - 1;
|
|
|
|
inlen -= n - 1;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2018-11-12 15:24:42 +08:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2018-03-27 09:17:19 +08:00
|
|
|
|
2018-04-17 11:43:20 +08:00
|
|
|
if (lwsi_state(h2n->swsi) == LRS_DEFERRING_ACTION) {
|
2018-04-26 15:27:02 +08:00
|
|
|
// lwsl_notice("appending because we are in LRS_DEFERRING_ACTION\n");
|
2018-04-17 11:43:20 +08:00
|
|
|
m = lws_buflist_append_segment(
|
2018-04-17 15:35:15 +08:00
|
|
|
&h2n->swsi->buflist,
|
2018-04-17 11:43:20 +08:00
|
|
|
in - 1, n);
|
|
|
|
if (m < 0)
|
|
|
|
return -1;
|
|
|
|
if (m) {
|
|
|
|
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
|
|
|
lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
|
2019-04-21 06:24:05 +01:00
|
|
|
lws_dll2_add_head(&h2n->swsi->dll_buflist, &pt->dll_buflist_owner);
|
2018-04-17 11:43:20 +08:00
|
|
|
}
|
|
|
|
in += n - 1;
|
|
|
|
h2n->inside += n;
|
|
|
|
h2n->count += n - 1;
|
|
|
|
inlen -= n - 1;
|
|
|
|
|
|
|
|
lwsl_debug("%s: deferred %d\n", __func__, n);
|
|
|
|
goto do_windows;
|
|
|
|
}
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
2018-04-11 13:39:42 +08:00
|
|
|
n = lws_read_h1(h2n->swsi, in - 1, n);
|
2018-04-25 08:42:18 +08:00
|
|
|
// lwsl_notice("%s: lws_read_h1 %d\n", __func__, n);
|
2018-03-27 09:17:19 +08:00
|
|
|
h2n->swsi->outer_will_close = 0;
|
|
|
|
/*
|
2018-04-11 13:39:42 +08:00
|
|
|
* can return 0 in POST body with
|
|
|
|
* content len exhausted somehow.
|
2018-03-27 09:17:19 +08:00
|
|
|
*/
|
2018-04-17 11:43:20 +08:00
|
|
|
if (n < 0 ||
|
2018-04-17 15:35:15 +08:00
|
|
|
(!n && !lws_buflist_next_segment_len(&wsi->buflist, NULL))) {
|
2018-04-17 11:43:20 +08:00
|
|
|
lwsl_info("%s: lws_read_h1 told %d %d / %d\n",
|
2018-04-11 13:39:42 +08:00
|
|
|
__func__, n, h2n->count, h2n->length);
|
2018-03-27 09:17:19 +08:00
|
|
|
in += h2n->length - h2n->count;
|
|
|
|
h2n->inside = h2n->length;
|
|
|
|
h2n->count = h2n->length - 1;
|
2018-04-11 13:39:42 +08:00
|
|
|
|
2018-04-25 08:42:18 +08:00
|
|
|
//if (n < 0)
|
|
|
|
// goto already_closed_swsi;
|
2018-03-27 09:17:19 +08:00
|
|
|
goto close_swsi_and_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
inlen -= n - 1;
|
|
|
|
in += n - 1;
|
|
|
|
h2n->inside += n;
|
|
|
|
h2n->count += n - 1;
|
|
|
|
}
|
2018-02-19 05:31:14 +08:00
|
|
|
|
2018-04-17 11:43:20 +08:00
|
|
|
do_windows:
|
2018-02-19 05:31:14 +08:00
|
|
|
/* account for both network and stream wsi windows */
|
|
|
|
|
|
|
|
wsi->h2.peer_tx_cr_est -= n;
|
|
|
|
h2n->swsi->h2.peer_tx_cr_est -= n;
|
|
|
|
|
|
|
|
// lwsl_notice(" peer_tx_cr_est %d, parent %d\n",
|
|
|
|
// h2n->swsi->h2.peer_tx_cr_est, wsi->h2.peer_tx_cr_est);
|
|
|
|
|
|
|
|
if (h2n->swsi->h2.peer_tx_cr_est < (int)(2 * h2n->length) + 65536) {
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
pps->u.update_window.sid = h2n->sid;
|
|
|
|
pps->u.update_window.credit = (2 * h2n->length + 65536);
|
|
|
|
h2n->swsi->h2.peer_tx_cr_est += pps->u.update_window.credit;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
}
|
|
|
|
if (wsi->h2.peer_tx_cr_est < (int)(2 * h2n->length) + 65536) {
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
pps->u.update_window.sid = 0;
|
|
|
|
pps->u.update_window.credit = (2 * h2n->length + 65536);
|
|
|
|
wsi->h2.peer_tx_cr_est += pps->u.update_window.credit;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
}
|
2018-02-06 09:58:48 +08:00
|
|
|
|
2018-02-19 05:31:14 +08:00
|
|
|
// lwsl_notice("%s: count %d len %d\n", __func__, (int)h2n->count, (int)h2n->length);
|
2018-02-06 09:58:48 +08:00
|
|
|
|
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;
|
|
|
|
} else {
|
|
|
|
h2n->weight_temp = c;
|
|
|
|
lwsl_info("PRIORITY: dep 0x%x, weight 0x%02X\n",
|
|
|
|
h2n->dep, h2n->weight_temp);
|
|
|
|
|
2018-11-03 14:47:48 +08:00
|
|
|
if ((h2n->dep & ~(1u << 31)) == h2n->sid) {
|
2018-02-19 05:31:14 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"cant depend on own sid");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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 */
|
|
|
|
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) {
|
2018-03-11 11:26:06 +08:00
|
|
|
lwsl_notice("%s: count > length %d %d\n",
|
|
|
|
__func__, h2n->count, h2n->length);
|
2018-04-02 11:55:17 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
2018-02-19 05:31:14 +08:00
|
|
|
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
|
|
|
|
*/
|
|
|
|
if (lws_h2_parse_end_of_frame(wsi))
|
|
|
|
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
|
|
|
|
|
|
|
if (h2n->frame_state == LWS_H2_FRAME_HEADER_LENGTH)
|
|
|
|
if (lws_h2_parse_frame_header(wsi))
|
|
|
|
goto fail;
|
|
|
|
break;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-04-02 11:55:17 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-11-25 10:10:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
*inused = in - oldin;
|
|
|
|
|
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:
|
2018-03-11 11:26:06 +08:00
|
|
|
*inused = in - oldin;
|
|
|
|
|
|
|
|
return 2;
|
|
|
|
|
2017-11-25 10:10:33 +08:00
|
|
|
fail:
|
|
|
|
*inused = in - oldin;
|
|
|
|
|
|
|
|
return 1;
|
2014-10-22 15:37:28 +08:00
|
|
|
}
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
int
|
|
|
|
lws_h2_client_handshake(struct lws *wsi)
|
|
|
|
{
|
2018-04-16 19:52:28 +08:00
|
|
|
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
|
|
|
uint8_t *buf, *start, *p, *end;
|
2018-03-27 09:17:19 +08:00
|
|
|
char *meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD),
|
|
|
|
*uri = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI);
|
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
|
|
|
struct lws_h2_protocol_send *pps;
|
|
|
|
int n;
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
int sid = nwsi->h2.h2n->highest_sid_opened + 2;
|
|
|
|
|
|
|
|
nwsi->h2.h2n->highest_sid_opened = sid;
|
|
|
|
wsi->h2.my_sid = sid;
|
|
|
|
|
|
|
|
lwsl_info("%s: CLIENT_WAITING_TO_SEND_HEADERS: pollout (sid %d)\n",
|
|
|
|
__func__, wsi->h2.my_sid);
|
|
|
|
|
|
|
|
pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
|
|
|
|
if (!pps)
|
|
|
|
return 1;
|
|
|
|
pps->u.update_window.sid = sid;
|
|
|
|
pps->u.update_window.credit = 4 * 65536;
|
|
|
|
wsi->h2.peer_tx_cr_est += pps->u.update_window.credit;
|
|
|
|
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;
|
|
|
|
pps->u.update_window.credit = 4 * 65536;
|
|
|
|
wsi->h2.peer_tx_cr_est += pps->u.update_window.credit;
|
|
|
|
lws_pps_schedule(wsi, pps);
|
|
|
|
|
2018-04-16 19:52:28 +08:00
|
|
|
p = start = buf = pt->serv_buf + LWS_PRE;
|
|
|
|
end = start + wsi->context->pt_serv_buf_size - LWS_PRE - 1;
|
|
|
|
|
2018-03-27 09:17:19 +08:00
|
|
|
/* it's time for us to send our client stream headers */
|
|
|
|
|
|
|
|
if (!meth)
|
|
|
|
meth = "GET";
|
|
|
|
|
|
|
|
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,
|
2018-08-14 08:00:25 +08:00
|
|
|
(unsigned char *)"https", 4,
|
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
|
|
|
|
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_PATH,
|
|
|
|
(unsigned char *)uri,
|
|
|
|
lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI),
|
|
|
|
&p, end))
|
2018-04-16 19:52:28 +08:00
|
|
|
goto fail_length;
|
2018-03-27 09:17:19 +08:00
|
|
|
|
|
|
|
if (lws_add_http_header_by_token(wsi,
|
|
|
|
WSI_TOKEN_HTTP_COLON_AUTHORITY,
|
2018-04-16 19:52:28 +08:00
|
|
|
(unsigned char *)lws_hdr_simple_ptr(wsi,
|
|
|
|
_WSI_TOKEN_CLIENT_ORIGIN),
|
2018-11-23 08:47:56 +08:00
|
|
|
lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_ORIGIN),
|
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
|
|
|
|
|
|
|
/* give userland a chance to append, eg, cookies */
|
|
|
|
|
|
|
|
if (wsi->protocol->callback(wsi,
|
|
|
|
LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
|
|
|
|
wsi->user_space, &p, (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
|
|
|
|
|
|
|
n = lws_write(wsi, start, p - start,
|
|
|
|
LWS_WRITE_HTTP_HEADERS);
|
|
|
|
if (n != (p - start)) {
|
|
|
|
lwsl_err("_write returned %d from %ld\n", n,
|
|
|
|
(long)(p - start));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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;
|
2018-03-11 11:26:06 +08:00
|
|
|
int n, m;
|
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 16:38:54 +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 */
|
|
|
|
wsi->protocol->name && wsi->protocol->name[0]) {
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
|
|
|
|
(unsigned char *)wsi->protocol->name,
|
|
|
|
(int)strlen(wsi->protocol->name),
|
|
|
|
&p, end))
|
|
|
|
return -1;
|
|
|
|
}
|
2017-11-14 07:35:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
|
|
|
return -1;
|
|
|
|
|
2018-03-11 11:26:06 +08:00
|
|
|
m = lws_ptr_diff(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);
|
|
|
|
if (n != m) {
|
|
|
|
lwsl_err("_write returned %d from %d\n", n, 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 &&
|
|
|
|
wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO, wsi->user_space,
|
|
|
|
(void *)hit->cgienv, 0))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
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;
|
|
|
|
lws_filepos_t body_chunk_len;
|
|
|
|
|
|
|
|
// 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) {
|
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)) {
|
|
|
|
lws_rxflow_cache(wsi, buf, 0, (int)len);
|
|
|
|
buf += len;
|
2018-04-20 10:33:23 +08:00
|
|
|
len = 0;
|
2018-04-11 13:39:42 +08:00
|
|
|
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;
|
|
|
|
len -= body_chunk_len;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf += body_chunk_len;
|
|
|
|
len -= body_chunk_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lws_ptr_diff(buf, oldbuf);
|
|
|
|
}
|
|
|
|
|