2014-10-12 08:38:16 +08:00
|
|
|
/*
|
2019-08-14 10:44:14 +01:00
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
2014-10-12 08:38:16 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
2014-10-12 08:38:16 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to
|
|
|
|
* deal in the Software without restriction, including without limitation the
|
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2014-10-12 08:38:16 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
2014-10-12 08:38:16 +08:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
* IN THE SOFTWARE.
|
2014-10-12 08:38:16 +08:00
|
|
|
*/
|
|
|
|
|
2019-08-15 10:49:52 +01:00
|
|
|
#include "private-lib-core.h"
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
/*
|
|
|
|
* Official static header table for HPACK
|
|
|
|
* +-------+-----------------------------+---------------+
|
|
|
|
| 1 | :authority | |
|
|
|
|
| 2 | :method | GET |
|
|
|
|
| 3 | :method | POST |
|
|
|
|
| 4 | :path | / |
|
|
|
|
| 5 | :path | /index.html |
|
|
|
|
| 6 | :scheme | http |
|
|
|
|
| 7 | :scheme | https |
|
|
|
|
| 8 | :status | 200 |
|
|
|
|
| 9 | :status | 204 |
|
|
|
|
| 10 | :status | 206 |
|
|
|
|
| 11 | :status | 304 |
|
|
|
|
| 12 | :status | 400 |
|
|
|
|
| 13 | :status | 404 |
|
|
|
|
| 14 | :status | 500 |
|
|
|
|
| 15 | accept-charset | |
|
|
|
|
| 16 | accept-encoding | gzip, deflate |
|
|
|
|
| 17 | accept-language | |
|
|
|
|
| 18 | accept-ranges | |
|
|
|
|
| 19 | accept | |
|
|
|
|
| 20 | access-control-allow-origin | |
|
|
|
|
| 21 | age | |
|
|
|
|
| 22 | allow | |
|
|
|
|
| 23 | authorization | |
|
|
|
|
| 24 | cache-control | |
|
|
|
|
| 25 | content-disposition | |
|
|
|
|
| 26 | content-encoding | |
|
|
|
|
| 27 | content-language | |
|
|
|
|
| 28 | content-length | |
|
|
|
|
| 29 | content-location | |
|
|
|
|
| 30 | content-range | |
|
|
|
|
| 31 | content-type | |
|
|
|
|
| 32 | cookie | |
|
|
|
|
| 33 | date | |
|
|
|
|
| 34 | etag | |
|
|
|
|
| 35 | expect | |
|
|
|
|
| 36 | expires | |
|
|
|
|
| 37 | from | |
|
|
|
|
| 38 | host | |
|
|
|
|
| 39 | if-match | |
|
|
|
|
| 40 | if-modified-since | |
|
|
|
|
| 41 | if-none-match | |
|
|
|
|
| 42 | if-range | |
|
|
|
|
| 43 | if-unmodified-since | |
|
|
|
|
| 44 | last-modified | |
|
|
|
|
| 45 | link | |
|
|
|
|
| 46 | location | |
|
|
|
|
| 47 | max-forwards | |
|
|
|
|
| 48 | proxy-authenticate | |
|
|
|
|
| 49 | proxy-authorization | |
|
|
|
|
| 50 | range | |
|
|
|
|
| 51 | referer | |
|
|
|
|
| 52 | refresh | |
|
|
|
|
| 53 | retry-after | |
|
|
|
|
| 54 | server | |
|
|
|
|
| 55 | set-cookie | |
|
|
|
|
| 56 | strict-transport-security | |
|
|
|
|
| 57 | transfer-encoding | |
|
|
|
|
| 58 | user-agent | |
|
|
|
|
| 59 | vary | |
|
|
|
|
| 60 | via | |
|
|
|
|
| 61 | www-authenticate | |
|
|
|
|
+-------+-----------------------------+---------------+
|
|
|
|
*/
|
|
|
|
|
2017-11-05 09:02:16 +08:00
|
|
|
static const uint8_t static_hdr_len[62] = {
|
2017-10-13 10:33:02 +08:00
|
|
|
0, /* starts at 1 */
|
2017-11-05 09:02:16 +08:00
|
|
|
10, 7, 7, 5, 5, 7, 7, 7, 7, 7,
|
|
|
|
7, 7, 7, 7, 14, 15, 15, 13, 6, 27,
|
|
|
|
3, 5, 13, 13, 19, 16, 16, 14, 16, 13,
|
|
|
|
12, 6, 4, 4, 6, 7, 4, 4, 8, 17,
|
|
|
|
13, 8, 19, 13, 4, 8, 12, 18, 19, 5,
|
|
|
|
7, 7, 11, 6, 10, 25, 17, 10, 4, 3,
|
|
|
|
16
|
2017-10-13 10:33:02 +08:00
|
|
|
};
|
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
static const unsigned char static_token[] = {
|
|
|
|
0,
|
|
|
|
WSI_TOKEN_HTTP_COLON_AUTHORITY,
|
|
|
|
WSI_TOKEN_HTTP_COLON_METHOD,
|
|
|
|
WSI_TOKEN_HTTP_COLON_METHOD,
|
|
|
|
WSI_TOKEN_HTTP_COLON_PATH,
|
|
|
|
WSI_TOKEN_HTTP_COLON_PATH,
|
|
|
|
WSI_TOKEN_HTTP_COLON_SCHEME,
|
|
|
|
WSI_TOKEN_HTTP_COLON_SCHEME,
|
|
|
|
WSI_TOKEN_HTTP_COLON_STATUS,
|
|
|
|
WSI_TOKEN_HTTP_COLON_STATUS,
|
|
|
|
WSI_TOKEN_HTTP_COLON_STATUS,
|
|
|
|
WSI_TOKEN_HTTP_COLON_STATUS,
|
|
|
|
WSI_TOKEN_HTTP_COLON_STATUS,
|
|
|
|
WSI_TOKEN_HTTP_COLON_STATUS,
|
|
|
|
WSI_TOKEN_HTTP_COLON_STATUS,
|
|
|
|
WSI_TOKEN_HTTP_ACCEPT_CHARSET,
|
|
|
|
WSI_TOKEN_HTTP_ACCEPT_ENCODING,
|
|
|
|
WSI_TOKEN_HTTP_ACCEPT_LANGUAGE,
|
|
|
|
WSI_TOKEN_HTTP_ACCEPT_RANGES,
|
|
|
|
WSI_TOKEN_HTTP_ACCEPT,
|
|
|
|
WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,
|
|
|
|
WSI_TOKEN_HTTP_AGE,
|
|
|
|
WSI_TOKEN_HTTP_ALLOW,
|
|
|
|
WSI_TOKEN_HTTP_AUTHORIZATION,
|
|
|
|
WSI_TOKEN_HTTP_CACHE_CONTROL,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_ENCODING,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_LANGUAGE,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_LOCATION,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_RANGE,
|
|
|
|
WSI_TOKEN_HTTP_CONTENT_TYPE,
|
|
|
|
WSI_TOKEN_HTTP_COOKIE,
|
|
|
|
WSI_TOKEN_HTTP_DATE,
|
|
|
|
WSI_TOKEN_HTTP_ETAG,
|
|
|
|
WSI_TOKEN_HTTP_EXPECT,
|
|
|
|
WSI_TOKEN_HTTP_EXPIRES,
|
|
|
|
WSI_TOKEN_HTTP_FROM,
|
2014-10-12 08:38:16 +08:00
|
|
|
WSI_TOKEN_HOST,
|
2014-10-09 16:57:47 +08:00
|
|
|
WSI_TOKEN_HTTP_IF_MATCH,
|
|
|
|
WSI_TOKEN_HTTP_IF_MODIFIED_SINCE,
|
|
|
|
WSI_TOKEN_HTTP_IF_NONE_MATCH,
|
|
|
|
WSI_TOKEN_HTTP_IF_RANGE,
|
|
|
|
WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE,
|
|
|
|
WSI_TOKEN_HTTP_LAST_MODIFIED,
|
|
|
|
WSI_TOKEN_HTTP_LINK,
|
|
|
|
WSI_TOKEN_HTTP_LOCATION,
|
|
|
|
WSI_TOKEN_HTTP_MAX_FORWARDS,
|
|
|
|
WSI_TOKEN_HTTP_PROXY_AUTHENTICATE,
|
|
|
|
WSI_TOKEN_HTTP_PROXY_AUTHORIZATION,
|
|
|
|
WSI_TOKEN_HTTP_RANGE,
|
|
|
|
WSI_TOKEN_HTTP_REFERER,
|
|
|
|
WSI_TOKEN_HTTP_REFRESH,
|
|
|
|
WSI_TOKEN_HTTP_RETRY_AFTER,
|
|
|
|
WSI_TOKEN_HTTP_SERVER,
|
|
|
|
WSI_TOKEN_HTTP_SET_COOKIE,
|
|
|
|
WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY,
|
|
|
|
WSI_TOKEN_HTTP_TRANSFER_ENCODING,
|
|
|
|
WSI_TOKEN_HTTP_USER_AGENT,
|
|
|
|
WSI_TOKEN_HTTP_VARY,
|
|
|
|
WSI_TOKEN_HTTP_VIA,
|
|
|
|
WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
|
|
|
|
};
|
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
/* some of the entries imply values as well as header names */
|
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
static const char * const http2_canned[] = {
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
"GET",
|
|
|
|
"POST",
|
|
|
|
"/",
|
|
|
|
"/index.html",
|
|
|
|
"http",
|
|
|
|
"https",
|
|
|
|
"200",
|
|
|
|
"204",
|
|
|
|
"206",
|
|
|
|
"304",
|
|
|
|
"400",
|
|
|
|
"404",
|
|
|
|
"500",
|
|
|
|
"",
|
|
|
|
"gzip, deflate"
|
|
|
|
};
|
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
/* see minihuf.c */
|
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
#include "huftable.h"
|
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
static int huftable_decode(int pos, char c)
|
2014-10-09 16:57:47 +08:00
|
|
|
{
|
|
|
|
int q = pos + !!c;
|
|
|
|
|
|
|
|
if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */
|
|
|
|
return lextable[q] | 0x8000;
|
|
|
|
|
|
|
|
return pos + (lextable[q] << 1);
|
|
|
|
}
|
|
|
|
|
2015-12-04 11:08:32 +08:00
|
|
|
static int lws_frag_start(struct lws *wsi, int hdr_token_idx)
|
2014-10-09 16:57:47 +08:00
|
|
|
{
|
2018-04-27 15:20:56 +08:00
|
|
|
struct allocated_headers *ah = wsi->http.ah;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (!ah) {
|
|
|
|
lwsl_notice("%s: no ah\n", __func__);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ah->hdr_token_idx = -1;
|
|
|
|
|
|
|
|
lwsl_header("%s: token %d ah->pos = %d, ah->nfrag = %d\n",
|
|
|
|
__func__, hdr_token_idx, ah->pos, ah->nfrag);
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2016-04-10 09:33:54 +08:00
|
|
|
if (!hdr_token_idx) {
|
|
|
|
lwsl_err("%s: zero hdr_token_idx\n", __func__);
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2016-04-10 09:33:54 +08:00
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-08-16 19:10:32 +08:00
|
|
|
if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frag_index)) {
|
2016-04-10 09:33:54 +08:00
|
|
|
lwsl_err("%s: frag index %d too big\n", __func__, ah->nfrag);
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2016-04-10 09:33:54 +08:00
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if ((hdr_token_idx == WSI_TOKEN_HTTP_COLON_AUTHORITY ||
|
|
|
|
hdr_token_idx == WSI_TOKEN_HTTP_COLON_METHOD ||
|
|
|
|
hdr_token_idx == WSI_TOKEN_HTTP_COLON_PATH ||
|
2017-11-14 07:35:05 +08:00
|
|
|
hdr_token_idx == WSI_TOKEN_COLON_PROTOCOL ||
|
2017-10-13 10:33:02 +08:00
|
|
|
hdr_token_idx == WSI_TOKEN_HTTP_COLON_SCHEME) &&
|
|
|
|
ah->frag_index[hdr_token_idx]) {
|
|
|
|
if (!(ah->frags[ah->frag_index[hdr_token_idx]].flags & 1)) {
|
|
|
|
lws_h2_goaway(lws_get_network_wsi(wsi),
|
|
|
|
H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Duplicated pseudoheader");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ah->nfrag == 0)
|
|
|
|
ah->nfrag = 1;
|
|
|
|
|
2015-12-15 21:15:58 +08:00
|
|
|
ah->frags[ah->nfrag].offset = ah->pos;
|
|
|
|
ah->frags[ah->nfrag].len = 0;
|
|
|
|
ah->frags[ah->nfrag].nfrag = 0;
|
2017-10-13 10:33:02 +08:00
|
|
|
ah->frags[ah->nfrag].flags = 2; /* we had reason to set it */
|
|
|
|
|
|
|
|
ah->hdr_token_idx = hdr_token_idx;
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2017-12-01 11:07:00 +08:00
|
|
|
/*
|
|
|
|
* Okay, but we could be, eg, the second or subsequent cookie: header
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (ah->frag_index[hdr_token_idx]) {
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/* find the last fragment for this header... */
|
|
|
|
n = ah->frag_index[hdr_token_idx];
|
|
|
|
while (ah->frags[n].nfrag)
|
|
|
|
n = ah->frags[n].nfrag;
|
|
|
|
/* and point it to continue in our continuation fragment */
|
|
|
|
ah->frags[n].nfrag = ah->nfrag;
|
|
|
|
} else
|
|
|
|
ah->frag_index[hdr_token_idx] = ah->nfrag;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-04 11:08:32 +08:00
|
|
|
static int lws_frag_append(struct lws *wsi, unsigned char c)
|
2014-10-12 08:38:16 +08:00
|
|
|
{
|
2018-04-27 15:20:56 +08:00
|
|
|
struct allocated_headers *ah = wsi->http.ah;
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->data[ah->pos++] = (char)c;
|
2015-12-15 21:15:58 +08:00
|
|
|
ah->frags[ah->nfrag].len++;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
return (unsigned int)ah->pos >= wsi->a.context->max_http_header_data;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
|
|
|
|
2015-12-04 11:08:32 +08:00
|
|
|
static int lws_frag_end(struct lws *wsi)
|
2014-10-12 08:38:16 +08:00
|
|
|
{
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_header("%s\n", __func__);
|
2014-10-12 08:38:16 +08:00
|
|
|
if (lws_frag_append(wsi, 0))
|
|
|
|
return 1;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/* don't account for the terminating NUL in the logical length */
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2018-04-27 15:20:56 +08:00
|
|
|
wsi->http.ah->nfrag++;
|
2014-10-12 08:38:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
int
|
|
|
|
lws_hdr_extant(struct lws *wsi, enum lws_token_indexes h)
|
|
|
|
{
|
2018-04-27 15:20:56 +08:00
|
|
|
struct allocated_headers *ah = wsi->http.ah;
|
2017-10-13 10:33:02 +08:00
|
|
|
int n;
|
|
|
|
|
|
|
|
if (!ah)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
n = ah->frag_index[h];
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return !!(ah->frags[n].flags & 2);
|
|
|
|
}
|
|
|
|
|
2015-12-04 11:08:32 +08:00
|
|
|
static void lws_dump_header(struct lws *wsi, int hdr)
|
2014-10-12 08:38:16 +08:00
|
|
|
{
|
|
|
|
char s[200];
|
2017-10-13 10:33:02 +08:00
|
|
|
const unsigned char *p;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (hdr == LWS_HPACK_IGNORE_ENTRY) {
|
|
|
|
lwsl_notice("hdr tok ignored\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void)p;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
len = lws_hdr_copy(wsi, s, sizeof(s) - 1, (enum lws_token_indexes)hdr);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (len < 0)
|
|
|
|
strcpy(s, "(too big to show)");
|
|
|
|
else
|
|
|
|
s[len] = '\0';
|
2020-08-18 11:32:44 +01:00
|
|
|
#if defined(_DEBUG)
|
2020-12-12 06:21:40 +00:00
|
|
|
p = lws_token_to_string((enum lws_token_indexes)hdr);
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_header(" hdr tok %d (%s) = '%s' (len %d)\n", hdr,
|
|
|
|
p ? (char *)p : (char *)"null", s, len);
|
2020-08-18 11:32:44 +01:00
|
|
|
#endif
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* dynamic table
|
|
|
|
*
|
|
|
|
* [ 0 .... num_entries - 1]
|
|
|
|
*
|
|
|
|
* Starts filling at 0+
|
|
|
|
*
|
|
|
|
* #62 is *most recently entered*
|
|
|
|
*
|
|
|
|
* Number of entries is not restricted, but aggregated size of the entry
|
|
|
|
* payloads is. Unfortunately the way HPACK does this is specific to an
|
|
|
|
* imagined implementation, and lws implementation is much more efficient
|
|
|
|
* (ignoring unknown headers and using the lws token index for the header
|
|
|
|
* name part).
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* returns 0 if dynamic entry (arg and len are filled)
|
|
|
|
* returns -1 if failure
|
|
|
|
* returns nonzero token index if actually static token
|
|
|
|
*/
|
2015-12-06 10:05:37 +08:00
|
|
|
static int
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,
|
|
|
|
uint32_t *hdr_len)
|
2014-10-12 08:38:16 +08:00
|
|
|
{
|
2014-10-18 12:23:05 +08:00
|
|
|
struct hpack_dynamic_table *dyn;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (index == LWS_HPACK_IGNORE_ENTRY)
|
|
|
|
return LWS_HPACK_IGNORE_ENTRY;
|
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
/* dynamic table only belongs to network wsi */
|
2017-10-13 10:33:02 +08:00
|
|
|
wsi = lws_get_network_wsi(wsi);
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!wsi->h2.h2n)
|
2017-10-13 10:33:02 +08:00
|
|
|
return -1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
dyn = &wsi->h2.h2n->hpack_dyn_table;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (index < 0)
|
|
|
|
return -1;
|
|
|
|
|
2018-08-16 19:10:32 +08:00
|
|
|
if (index < (int)LWS_ARRAY_SIZE(static_token)) {
|
|
|
|
if (arg && index < (int)LWS_ARRAY_SIZE(http2_canned)) {
|
2017-10-13 10:33:02 +08:00
|
|
|
*arg = http2_canned[index];
|
2017-10-25 08:00:23 +08:00
|
|
|
*len = (int)strlen(http2_canned[index]);
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
if (hdr_len)
|
|
|
|
*hdr_len = static_hdr_len[index];
|
2014-10-18 12:23:05 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
return static_token[index];
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2014-10-18 12:23:05 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!dyn) {
|
|
|
|
lwsl_notice("no dynamic table\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-09-19 10:15:56 +01:00
|
|
|
if (index >= (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries) {
|
2018-04-26 15:27:02 +08:00
|
|
|
lwsl_info(" %s: adjusted index %d >= %d\n", __func__, index,
|
2019-10-10 16:37:38 +01:00
|
|
|
(int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries);
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"index out of range");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2018-08-16 19:10:32 +08:00
|
|
|
index -= (int)LWS_ARRAY_SIZE(static_token);
|
2020-08-14 08:46:31 +01:00
|
|
|
index = lws_safe_modulo(dyn->pos - 1 - index, dyn->num_entries);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (index < 0)
|
|
|
|
index += dyn->num_entries;
|
|
|
|
|
2017-10-16 12:52:32 +08:00
|
|
|
lwsl_header("%s: dyn index %d, tok %d\n", __func__, index,
|
|
|
|
dyn->entries[index].lws_hdr_idx);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
if (arg && len) {
|
2017-10-13 10:33:02 +08:00
|
|
|
*arg = dyn->entries[index].value;
|
|
|
|
*len = dyn->entries[index].value_len;
|
2014-10-18 12:23:05 +08:00
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (hdr_len)
|
|
|
|
*hdr_len = dyn->entries[index].hdr_len;
|
|
|
|
|
|
|
|
return dyn->entries[index].lws_hdr_idx;
|
2014-10-18 12:23:05 +08:00
|
|
|
}
|
|
|
|
|
2015-12-06 10:05:37 +08:00
|
|
|
static int
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_dynamic_table_dump(struct lws *wsi)
|
2014-10-18 12:23:05 +08:00
|
|
|
{
|
2017-10-13 10:33:02 +08:00
|
|
|
#if 0
|
|
|
|
struct lws *nwsi = lws_get_network_wsi(wsi);
|
2014-10-18 12:23:05 +08:00
|
|
|
struct hpack_dynamic_table *dyn;
|
2017-10-13 10:33:02 +08:00
|
|
|
int n, m;
|
|
|
|
const char *p;
|
2014-10-18 12:23:05 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!nwsi->h2.h2n)
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
2017-12-01 11:09:32 +08:00
|
|
|
dyn = &nwsi->h2.h2n->hpack_dyn_table;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2020-12-25 05:54:19 +00:00
|
|
|
lwsl_header("Dump dyn table for nwsi %s (%d / %d members, pos = %d, "
|
|
|
|
"start index %d, virt used %d / %d)\n", lws_wsi_tag(nwsi),
|
2017-10-16 12:52:32 +08:00
|
|
|
dyn->used_entries, dyn->num_entries, dyn->pos,
|
2018-08-16 19:10:32 +08:00
|
|
|
(uint32_t)LWS_ARRAY_SIZE(static_token),
|
2017-10-16 12:52:32 +08:00
|
|
|
dyn->virtual_payload_usage, dyn->virtual_payload_max);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
for (n = 0; n < dyn->used_entries; n++) {
|
2020-08-14 08:46:31 +01:00
|
|
|
m = lws_safe_modulo(dyn->pos - 1 - n, dyn->num_entries);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (m < 0)
|
|
|
|
m += dyn->num_entries;
|
|
|
|
if (dyn->entries[m].lws_hdr_idx != LWS_HPACK_IGNORE_ENTRY)
|
|
|
|
p = (const char *)lws_token_to_string(
|
|
|
|
dyn->entries[m].lws_hdr_idx);
|
|
|
|
else
|
|
|
|
p = "(ignored)";
|
|
|
|
lwsl_header(" %3d: tok %s: (len %d) val '%s'\n",
|
2018-08-16 19:10:32 +08:00
|
|
|
(int)(n + LWS_ARRAY_SIZE(static_token)), p,
|
2017-10-16 12:52:32 +08:00
|
|
|
dyn->entries[m].hdr_len, dyn->entries[m].value ?
|
|
|
|
dyn->entries[m].value : "null");
|
2014-10-18 12:23:05 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)
|
|
|
|
{
|
|
|
|
lwsl_header("freeing %d for reuse\n", idx);
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->virtual_payload_usage = (uint32_t)((unsigned int)dyn->virtual_payload_usage - (unsigned int)(dyn->entries[idx].value_len +
|
|
|
|
dyn->entries[idx].hdr_len));
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_free_set_NULL(dyn->entries[idx].value);
|
|
|
|
dyn->entries[idx].value = NULL;
|
|
|
|
dyn->entries[idx].value_len = 0;
|
|
|
|
dyn->entries[idx].hdr_len = 0;
|
|
|
|
dyn->entries[idx].lws_hdr_idx = LWS_HPACK_IGNORE_ENTRY;
|
|
|
|
dyn->used_entries--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There are two address spaces, 1) internal ringbuffer and 2) HPACK indexes.
|
|
|
|
*
|
|
|
|
* Internal ringbuffer:
|
|
|
|
*
|
|
|
|
* The internal ringbuffer wraps as we keep filling it, dyn->pos points to
|
|
|
|
* the next index to be written.
|
|
|
|
*
|
|
|
|
* HPACK indexes:
|
|
|
|
*
|
|
|
|
* The last-written entry becomes entry 0, the previously-last-written entry
|
|
|
|
* becomes entry 1 etc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
|
2020-12-12 06:21:40 +00:00
|
|
|
int lws_hdr_index, char *arg, size_t len)
|
2017-10-13 10:33:02 +08:00
|
|
|
{
|
|
|
|
struct hpack_dynamic_table *dyn;
|
2018-10-10 13:54:43 +08:00
|
|
|
int new_index;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/* dynamic table only belongs to network wsi */
|
|
|
|
wsi = lws_get_network_wsi(wsi);
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!wsi->h2.h2n)
|
2014-10-18 12:23:05 +08:00
|
|
|
return 1;
|
2017-12-01 11:09:32 +08:00
|
|
|
dyn = &wsi->h2.h2n->hpack_dyn_table;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (!dyn->entries) {
|
|
|
|
lwsl_err("%s: unsized dyn table\n", __func__);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
lws_h2_dynamic_table_dump(wsi);
|
|
|
|
|
2020-08-14 08:46:31 +01:00
|
|
|
new_index = lws_safe_modulo(dyn->pos, dyn->num_entries);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (dyn->num_entries && dyn->used_entries == dyn->num_entries) {
|
|
|
|
if (dyn->virtual_payload_usage < dyn->virtual_payload_max)
|
|
|
|
lwsl_err("Dropping header content before limit!\n");
|
|
|
|
/* we have to drop the oldest to make space */
|
|
|
|
lws_dynamic_free(dyn, new_index);
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
/*
|
|
|
|
* evict guys to make room, allowing for some overage. We have to
|
|
|
|
* take care about getting a single huge header, and evicting
|
|
|
|
* everything
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (dyn->virtual_payload_usage &&
|
|
|
|
dyn->used_entries &&
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->virtual_payload_usage + (unsigned int)hdr_len + len >
|
2017-10-13 10:33:02 +08:00
|
|
|
dyn->virtual_payload_max + 1024) {
|
2020-08-14 08:46:31 +01:00
|
|
|
int n = lws_safe_modulo(dyn->pos - dyn->used_entries,
|
|
|
|
dyn->num_entries);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (n < 0)
|
|
|
|
n += dyn->num_entries;
|
|
|
|
lws_dynamic_free(dyn, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dyn->used_entries < dyn->num_entries)
|
|
|
|
dyn->used_entries++;
|
|
|
|
|
|
|
|
dyn->entries[new_index].value_len = 0;
|
|
|
|
|
|
|
|
if (lws_hdr_index != LWS_HPACK_IGNORE_ENTRY) {
|
2017-10-16 12:52:32 +08:00
|
|
|
if (dyn->entries[new_index].value)
|
|
|
|
lws_free_set_NULL(dyn->entries[new_index].value);
|
2018-11-23 08:47:56 +08:00
|
|
|
dyn->entries[new_index].value =
|
|
|
|
lws_malloc(len + 1, "hpack dyn");
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!dyn->entries[new_index].value)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
memcpy(dyn->entries[new_index].value, arg, len);
|
|
|
|
dyn->entries[new_index].value[len] = '\0';
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->entries[new_index].value_len = (uint16_t)len;
|
2017-10-13 10:33:02 +08:00
|
|
|
} else
|
|
|
|
dyn->entries[new_index].value = NULL;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->entries[new_index].lws_hdr_idx = (uint16_t)lws_hdr_index;
|
|
|
|
dyn->entries[new_index].hdr_len = (uint16_t)hdr_len;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->virtual_payload_usage = (uint32_t)(dyn->virtual_payload_usage +
|
|
|
|
(unsigned int)hdr_len + len);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
lwsl_info("%s: index %ld: lws_hdr_index 0x%x, hdr len %d, '%s' len %d\n",
|
2018-08-16 19:10:32 +08:00
|
|
|
__func__, (long)LWS_ARRAY_SIZE(static_token),
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_hdr_index, hdr_len, dyn->entries[new_index].value ?
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->entries[new_index].value : "null", (int)len);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->pos = (uint16_t)lws_safe_modulo(dyn->pos + 1, dyn->num_entries);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
lws_h2_dynamic_table_dump(wsi);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_hpack_dynamic_size(struct lws *wsi, int size)
|
|
|
|
{
|
|
|
|
struct hpack_dynamic_table *dyn;
|
|
|
|
struct hpack_dt_entry *dte;
|
|
|
|
struct lws *nwsi;
|
|
|
|
int min, n = 0, m;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "size" here is coming from the http/2 SETTING
|
|
|
|
* SETTINGS_HEADER_TABLE_SIZE. This is a (virtual, in our case)
|
|
|
|
* linear buffer containing dynamic header names and values... when it
|
|
|
|
* is full, old entries are evicted.
|
|
|
|
*
|
|
|
|
* We encode the header as an lws_hdr_idx, which is all the rest of
|
|
|
|
* lws cares about; if there is no matching header we store an empty
|
|
|
|
* entry in the dyn table as a placeholder.
|
|
|
|
*
|
|
|
|
* So to make the two systems work together we keep an accounting of
|
|
|
|
* what we are using to decide when to evict... we must only evict
|
|
|
|
* things when the remote peer's accounting also makes him feel he
|
|
|
|
* should evict something.
|
|
|
|
*/
|
|
|
|
|
|
|
|
nwsi = lws_get_network_wsi(wsi);
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!nwsi->h2.h2n)
|
2017-10-13 10:33:02 +08:00
|
|
|
goto bail;
|
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
dyn = &nwsi->h2.h2n->hpack_dyn_table;
|
2019-11-05 21:00:45 +00:00
|
|
|
lwsl_info("%s: from %d to %d, lim %u\n", __func__,
|
2017-10-16 12:52:32 +08:00
|
|
|
(int)dyn->num_entries, size,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
(unsigned int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2019-07-08 11:33:52 +01:00
|
|
|
if (!size) {
|
|
|
|
size = dyn->num_entries * 8;
|
|
|
|
lws_hpack_destroy_dynamic_header(wsi);
|
|
|
|
}
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (size > (int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]) {
|
2018-04-26 15:27:02 +08:00
|
|
|
lwsl_info("rejecting hpack dyn size %u vs %u\n", size,
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
(unsigned int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
|
2018-04-26 15:27:02 +08:00
|
|
|
|
|
|
|
// this seems necessary to work with some browsers
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
if (nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE] == 65536 &&
|
2018-04-26 15:27:02 +08:00
|
|
|
size == 65537) { /* h2spec */
|
|
|
|
lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"Asked for header table bigger than we told");
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
size = (int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE];
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->virtual_payload_max = (uint32_t)size;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
size = size / 8;
|
|
|
|
min = size;
|
|
|
|
if (min > dyn->used_entries)
|
|
|
|
min = dyn->used_entries;
|
|
|
|
|
|
|
|
if (size == dyn->num_entries)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (dyn->num_entries < min)
|
|
|
|
min = dyn->num_entries;
|
|
|
|
|
2017-11-24 10:54:59 +08:00
|
|
|
// lwsl_notice("dte requested size %d\n", size);
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
dte = lws_zalloc(sizeof(*dte) * (unsigned int)(size + 1), "dynamic table entries");
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!dte)
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
while (dyn->virtual_payload_usage && dyn->used_entries &&
|
|
|
|
dyn->virtual_payload_usage > dyn->virtual_payload_max) {
|
2020-08-14 08:46:31 +01:00
|
|
|
n = lws_safe_modulo(dyn->pos - dyn->used_entries, dyn->num_entries);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (n < 0)
|
|
|
|
n += dyn->num_entries;
|
|
|
|
lws_dynamic_free(dyn, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (min > dyn->used_entries)
|
|
|
|
min = dyn->used_entries;
|
|
|
|
|
|
|
|
if (dyn->entries) {
|
|
|
|
for (n = 0; n < min; n++) {
|
2018-11-23 08:47:56 +08:00
|
|
|
m = (dyn->pos - dyn->used_entries + n) %
|
|
|
|
dyn->num_entries;
|
2017-10-13 10:33:02 +08:00
|
|
|
if (m < 0)
|
|
|
|
m += dyn->num_entries;
|
|
|
|
dte[n] = dyn->entries[m];
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_free(dyn->entries);
|
|
|
|
}
|
|
|
|
|
|
|
|
dyn->entries = dte;
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->num_entries = (uint16_t)size;
|
|
|
|
dyn->used_entries = (uint16_t)min;
|
2017-10-16 12:52:32 +08:00
|
|
|
if (size)
|
2020-12-12 06:21:40 +00:00
|
|
|
dyn->pos = (uint16_t)lws_safe_modulo(min, size);
|
2017-10-16 12:52:32 +08:00
|
|
|
else
|
|
|
|
dyn->pos = 0;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_dynamic_table_dump(wsi);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
return 0;
|
2014-12-04 23:59:35 +01:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
bail:
|
|
|
|
lwsl_info("%s: failed to resize to %d\n", __func__, size);
|
2014-12-04 23:59:35 +01:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
void
|
|
|
|
lws_hpack_destroy_dynamic_header(struct lws *wsi)
|
2014-10-12 08:38:16 +08:00
|
|
|
{
|
2017-10-13 10:33:02 +08:00
|
|
|
struct hpack_dynamic_table *dyn;
|
|
|
|
int n;
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
if (!wsi->h2.h2n)
|
2017-10-13 10:33:02 +08:00
|
|
|
return;
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
dyn = &wsi->h2.h2n->hpack_dyn_table;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (!dyn->entries)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (n = 0; n < dyn->num_entries; n++)
|
|
|
|
if (dyn->entries[n].value)
|
|
|
|
lws_free_set_NULL(dyn->entries[n].value);
|
|
|
|
|
|
|
|
lws_free_set_NULL(dyn->entries);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)
|
|
|
|
{
|
|
|
|
const char *arg = NULL;
|
|
|
|
int len = 0;
|
|
|
|
const char *p = NULL;
|
|
|
|
int tok = lws_token_from_index(wsi, idx, &arg, &len, NULL);
|
|
|
|
|
|
|
|
if (tok == LWS_HPACK_IGNORE_ENTRY) {
|
|
|
|
lwsl_header("%s: lws_token says ignore, returning\n", __func__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tok == -1) {
|
|
|
|
lwsl_info("%s: idx %d mapped to tok %d\n", __func__, idx, tok);
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (arg) {
|
|
|
|
/* dynamic result */
|
|
|
|
if (known_token > 0)
|
|
|
|
tok = known_token;
|
|
|
|
lwsl_header("%s: dyn: idx %d '%s' tok %d\n", __func__, idx, arg,
|
|
|
|
tok);
|
|
|
|
} else
|
|
|
|
lwsl_header("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_token_to_string((enum lws_token_indexes)tok));
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (tok == LWS_HPACK_IGNORE_ENTRY)
|
|
|
|
return 0;
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (arg)
|
|
|
|
p = arg;
|
|
|
|
|
2018-08-16 19:10:32 +08:00
|
|
|
if (idx < (int)LWS_ARRAY_SIZE(http2_canned))
|
2014-10-12 08:38:16 +08:00
|
|
|
p = http2_canned[idx];
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (lws_frag_start(wsi, tok))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
while (*p && len--)
|
2020-12-12 06:21:40 +00:00
|
|
|
if (lws_frag_append(wsi, (unsigned char)*p++))
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
if (lws_frag_end(wsi))
|
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
lws_dump_header(wsi, tok);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-23 15:12:17 +01:00
|
|
|
#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
|
2020-02-28 10:31:04 +00:00
|
|
|
static uint8_t lws_header_implies_psuedoheader_map[] = {
|
2020-03-06 15:22:36 +00:00
|
|
|
0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
2020-02-28 10:31:04 +00:00
|
|
|
};
|
|
|
|
#endif
|
2020-09-19 14:23:19 +01:00
|
|
|
#if !defined(LWS_HTTP_HEADERS_ALL) && defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
|
2020-02-28 10:31:04 +00:00
|
|
|
static uint8_t lws_header_implies_psuedoheader_map[] = {
|
2020-03-06 15:22:36 +00:00
|
|
|
0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
2020-02-28 10:31:04 +00:00
|
|
|
};
|
|
|
|
#endif
|
2020-04-23 15:12:17 +01:00
|
|
|
#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
|
2020-02-28 10:31:04 +00:00
|
|
|
static uint8_t lws_header_implies_psuedoheader_map[] = {
|
2020-03-06 15:22:36 +00:00
|
|
|
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
2020-02-28 10:31:04 +00:00
|
|
|
};
|
|
|
|
#endif
|
2020-09-19 14:23:19 +01:00
|
|
|
#if !defined(LWS_HTTP_HEADERS_ALL) && defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
|
2020-02-28 10:31:04 +00:00
|
|
|
static uint8_t lws_header_implies_psuedoheader_map[] = {
|
2020-03-06 15:22:36 +00:00
|
|
|
0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
|
2020-02-28 10:31:04 +00:00
|
|
|
};
|
|
|
|
#endif
|
2020-04-23 15:12:17 +01:00
|
|
|
#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
|
2020-02-28 10:31:04 +00:00
|
|
|
static uint8_t lws_header_implies_psuedoheader_map[] = {
|
2020-09-19 14:23:19 +01:00
|
|
|
0x03,0x00,0x80,0x0f,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
2020-02-28 10:31:04 +00:00
|
|
|
};
|
|
|
|
#endif
|
2020-09-19 14:23:19 +01:00
|
|
|
#if !defined(LWS_HTTP_HEADERS_ALL) && defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
|
2020-02-28 10:31:04 +00:00
|
|
|
static uint8_t lws_header_implies_psuedoheader_map[] = {
|
2020-09-19 14:23:19 +01:00
|
|
|
0x07,0x00,0x00,0x3e,0x00,0x00,0x00,0x80,0x03,0x09,0x00,0x00,0x00,0x00,0x00,0x00,
|
2020-02-28 10:31:04 +00:00
|
|
|
};
|
|
|
|
#endif
|
2020-04-23 15:12:17 +01:00
|
|
|
#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
|
2020-02-28 10:31:04 +00:00
|
|
|
static uint8_t lws_header_implies_psuedoheader_map[] = {
|
2020-09-19 14:23:19 +01:00
|
|
|
0x03,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,
|
2020-02-28 10:31:04 +00:00
|
|
|
};
|
|
|
|
#endif
|
2020-09-19 14:23:19 +01:00
|
|
|
#if defined(LWS_HTTP_HEADERS_ALL) || ( defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2))
|
2017-11-10 08:56:44 +08:00
|
|
|
static uint8_t lws_header_implies_psuedoheader_map[] = {
|
2020-09-19 14:23:19 +01:00
|
|
|
0x07,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x0e,0x24,0x00,0x00,0x00,0x00,0x00,
|
2017-11-10 08:56:44 +08:00
|
|
|
};
|
2020-02-28 10:31:04 +00:00
|
|
|
#endif
|
|
|
|
|
2020-09-19 14:23:19 +01:00
|
|
|
|
2017-11-10 08:56:44 +08:00
|
|
|
static int
|
|
|
|
lws_hpack_handle_pseudo_rules(struct lws *nwsi, struct lws *wsi, int m)
|
|
|
|
{
|
|
|
|
if (m == LWS_HPACK_IGNORE_ENTRY || m == -1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (wsi->seen_nonpseudoheader &&
|
|
|
|
(lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7)))) {
|
|
|
|
|
2018-04-26 15:27:02 +08:00
|
|
|
lwsl_info("lws tok %d seems to be a pseudoheader\n", m);
|
2017-11-10 08:56:44 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* it's not legal to see a
|
|
|
|
* pseudoheader after normal
|
|
|
|
* headers
|
|
|
|
*/
|
|
|
|
lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Pseudoheader after normal hdrs");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7))))
|
|
|
|
wsi->seen_nonpseudoheader = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
int lws_hpack_interpret(struct lws *wsi, unsigned char c)
|
2014-10-12 08:38:16 +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
|
|
|
struct lws_h2_netconn *h2n = nwsi->h2.h2n;
|
2018-04-27 15:20:56 +08:00
|
|
|
struct allocated_headers *ah = wsi->http.ah;
|
2014-10-12 08:38:16 +08:00
|
|
|
unsigned int prev;
|
|
|
|
unsigned char c1;
|
2018-03-07 18:15:17 +08:00
|
|
|
int n, m, plen;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (!h2n)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* HPKT_INDEXED_HDR_7 1xxxxxxx: just "header field"
|
|
|
|
* HPKT_INDEXED_HDR_6_VALUE_INCR 01xxxxxx: NEW indexed hdr + val
|
|
|
|
* HPKT_LITERAL_HDR_VALUE_INCR 01000000: NEW literal hdr + val
|
|
|
|
* HPKT_INDEXED_HDR_4_VALUE 0000xxxx: indexed hdr + val
|
|
|
|
* HPKT_INDEXED_HDR_4_VALUE_NEVER 0001xxxx: NEVER NEW indexed hdr + val
|
|
|
|
* HPKT_LITERAL_HDR_VALUE 00000000: literal hdr + val
|
|
|
|
* HPKT_LITERAL_HDR_VALUE_NEVER 00010000: NEVER NEW literal hdr + val
|
|
|
|
*/
|
|
|
|
switch (h2n->hpack) {
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
case HPKS_TYPE:
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->is_first_header_char = 1;
|
|
|
|
h2n->huff_pad = 0;
|
|
|
|
h2n->zero_huff_padding = 0;
|
|
|
|
h2n->last_action_dyntable_resize = 0;
|
|
|
|
h2n->ext_count = 0;
|
|
|
|
h2n->hpack_hdr_len = 0;
|
|
|
|
h2n->unknown_header = 0;
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->parser_state = 255;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (c & 0x80) { /* 1.... indexed header field only */
|
2014-10-12 08:38:16 +08:00
|
|
|
/* just a possibly-extended integer */
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hpack_type = HPKT_INDEXED_HDR_7;
|
|
|
|
lwsl_header("HPKT_INDEXED_HDR_7 hdr %d\n", c & 0x7f);
|
|
|
|
lws_h2_dynamic_table_dump(wsi);
|
|
|
|
|
|
|
|
h2n->hdr_idx = c & 0x7f;
|
2014-10-12 08:38:16 +08:00
|
|
|
if ((c & 0x7f) == 0x7f) {
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hpack_len = 0;
|
|
|
|
h2n->hpack_m = 0x7f;
|
|
|
|
h2n->hpack = HPKS_IDX_EXT;
|
2014-10-12 08:38:16 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!h2n->hdr_idx) {
|
|
|
|
lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"hdr index 0 seen");
|
|
|
|
return 1;
|
|
|
|
}
|
2017-11-10 08:56:44 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
m = lws_token_from_index(wsi, (int)h2n->hdr_idx,
|
2017-11-10 08:56:44 +08:00
|
|
|
NULL, NULL, NULL);
|
|
|
|
if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
|
|
|
|
return 1;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_header("HPKT_INDEXED_HDR_7: hdr %d\n", c & 0x7f);
|
|
|
|
if (lws_hpack_use_idx_hdr(wsi, c & 0x7f, -1)) {
|
|
|
|
lwsl_header("%s: idx hdr wr fail\n", __func__);
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2014-10-09 16:57:47 +08:00
|
|
|
/* stay at same state */
|
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
if (c & 0x40) { /* 01.... indexed or literal header incr idx */
|
2014-10-12 08:38:16 +08:00
|
|
|
/*
|
2017-10-13 10:33:02 +08:00
|
|
|
* [possibly-ext hdr idx (6) | new literal hdr name]
|
|
|
|
* H + possibly-ext value length
|
2014-10-12 08:38:16 +08:00
|
|
|
* literal value
|
|
|
|
*/
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hdr_idx = 0;
|
|
|
|
if (c == 0x40) { /* literal header */
|
|
|
|
lwsl_header(" HPKT_LITERAL_HDR_VALUE_INCR\n");
|
|
|
|
h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
|
|
|
|
h2n->value = 0;
|
|
|
|
h2n->hpack_len = 0;
|
|
|
|
h2n->hpack = HPKS_HLEN;
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
/* indexed header */
|
|
|
|
h2n->hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_header(" HPKT_INDEXED_HDR_6_VALUE_INCR (hdr %d)\n",
|
2017-10-13 10:33:02 +08:00
|
|
|
c & 0x3f);
|
|
|
|
h2n->hdr_idx = c & 0x3f;
|
2014-10-12 08:38:16 +08:00
|
|
|
if ((c & 0x3f) == 0x3f) {
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hpack_m = 0x3f;
|
|
|
|
h2n->hpack_len = 0;
|
|
|
|
h2n->hpack = HPKS_IDX_EXT;
|
2014-10-12 08:38:16 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
h2n->value = 1;
|
|
|
|
h2n->hpack = HPKS_HLEN;
|
|
|
|
if (!h2n->hdr_idx) {
|
|
|
|
lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"hdr index 0 seen");
|
|
|
|
return 1;
|
|
|
|
}
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch(c & 0xf0) {
|
2014-10-12 08:38:16 +08:00
|
|
|
case 0x10: /* literal header never index */
|
2017-10-13 10:33:02 +08:00
|
|
|
case 0: /* literal header without indexing */
|
2015-12-14 08:52:03 +08:00
|
|
|
/*
|
2014-10-12 08:38:16 +08:00
|
|
|
* follows 0x40 except 4-bit hdr idx
|
|
|
|
* and don't add to index
|
|
|
|
*/
|
2014-10-09 16:57:47 +08:00
|
|
|
if (c == 0) { /* literal name */
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hpack_type = HPKT_LITERAL_HDR_VALUE;
|
|
|
|
lwsl_header(" HPKT_LITERAL_HDR_VALUE\n");
|
|
|
|
h2n->hpack = HPKS_HLEN;
|
|
|
|
h2n->value = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (c == 0x10) { /* literal name NEVER */
|
|
|
|
h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_NEVER;
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_header(" HPKT_LITERAL_HDR_VALUE_NEVER\n");
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hpack = HPKS_HLEN;
|
|
|
|
h2n->value = 0;
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_header("indexed\n");
|
2014-10-09 16:57:47 +08:00
|
|
|
/* indexed name */
|
2017-10-13 10:33:02 +08:00
|
|
|
if (c & 0x10) {
|
|
|
|
h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE_NEVER;
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_header("HPKT_LITERAL_HDR_4_VALUE_NEVER\n");
|
2017-10-13 10:33:02 +08:00
|
|
|
} else {
|
|
|
|
h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE;
|
|
|
|
lwsl_header(" HPKT_INDEXED_HDR_4_VALUE\n");
|
|
|
|
}
|
|
|
|
h2n->hdr_idx = 0;
|
2014-10-12 08:38:16 +08:00
|
|
|
if ((c & 0xf) == 0xf) {
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hpack_len = c & 0xf;
|
|
|
|
h2n->hpack_m = 0xf;
|
|
|
|
h2n->hpack_len = 0;
|
|
|
|
h2n->hpack = HPKS_IDX_EXT;
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hdr_idx = c & 0xf;
|
|
|
|
h2n->value = 1;
|
|
|
|
h2n->hpack = HPKS_HLEN;
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
case 0x20:
|
|
|
|
case 0x30: /* header table size update */
|
2014-10-12 08:38:16 +08:00
|
|
|
/* possibly-extended size value (5) */
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_header("HPKT_SIZE_5 %x\n", c &0x1f);
|
|
|
|
h2n->hpack_type = HPKT_SIZE_5;
|
|
|
|
h2n->hpack_len = c & 0x1f;
|
|
|
|
if (h2n->hpack_len == 0x1f) {
|
|
|
|
h2n->hpack_m = 0x1f;
|
|
|
|
h2n->hpack_len = 0;
|
|
|
|
h2n->hpack = HPKS_IDX_EXT;
|
2014-10-12 08:38:16 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->last_action_dyntable_resize = 1;
|
2020-12-12 06:21:40 +00:00
|
|
|
if (lws_hpack_dynamic_size(wsi, (int)h2n->hpack_len))
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
}
|
2014-10-12 08:38:16 +08:00
|
|
|
break;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
case HPKS_IDX_EXT:
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->hpack_len = (uint32_t)((unsigned int)h2n->hpack_len |
|
|
|
|
(unsigned int)((c & 0x7f) << h2n->ext_count));
|
|
|
|
h2n->ext_count = (uint8_t)(h2n->ext_count + 7);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (c & 0x80) /* extended int not complete yet */
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* extended integer done */
|
|
|
|
h2n->hpack_len += h2n->hpack_m;
|
2019-11-05 21:00:45 +00:00
|
|
|
lwsl_header("HPKS_IDX_EXT: hpack_len %u\n", (unsigned int)h2n->hpack_len);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
switch (h2n->hpack_type) {
|
|
|
|
case HPKT_INDEXED_HDR_7:
|
2020-12-12 06:21:40 +00:00
|
|
|
if (lws_hpack_use_idx_hdr(wsi, (int)h2n->hpack_len,
|
|
|
|
(int)h2n->hdr_idx)) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_notice("%s: hd7 use fail\n", __func__);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
h2n->hpack = HPKS_TYPE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case HPKT_SIZE_5:
|
|
|
|
h2n->last_action_dyntable_resize = 1;
|
2020-12-12 06:21:40 +00:00
|
|
|
if (lws_hpack_dynamic_size(wsi, (int)h2n->hpack_len))
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
|
|
|
h2n->hpack = HPKS_TYPE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
h2n->hdr_idx = h2n->hpack_len;
|
|
|
|
if (!h2n->hdr_idx) {
|
|
|
|
lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"extended header index was 0");
|
|
|
|
return 1;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->value = 1;
|
|
|
|
h2n->hpack = HPKS_HLEN;
|
|
|
|
break;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case HPKS_HLEN: /* [ H | 7+ ] */
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->huff = !!(c & 0x80);
|
|
|
|
h2n->hpack_pos = 0;
|
|
|
|
h2n->hpack_len = c & 0x7f;
|
|
|
|
|
|
|
|
if (h2n->hpack_len == 0x7f) {
|
|
|
|
h2n->hpack_m = 0x7f;
|
|
|
|
h2n->hpack_len = 0;
|
|
|
|
h2n->ext_count = 0;
|
|
|
|
h2n->hpack = HPKS_HLEN_EXT;
|
|
|
|
break;
|
|
|
|
}
|
2019-10-10 16:37:38 +01:00
|
|
|
|
|
|
|
if (h2n->value && !h2n->hpack_len) {
|
|
|
|
lwsl_debug("%s: zero-length header data\n", __func__);
|
|
|
|
h2n->hpack = HPKS_TYPE;
|
|
|
|
goto fin;
|
|
|
|
}
|
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
pre_data:
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hpack = HPKS_DATA;
|
|
|
|
if (!h2n->value || !h2n->hdr_idx) {
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->parser_state = WSI_TOKEN_NAME_PART;
|
|
|
|
ah->lextable_pos = 0;
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->unknown_header = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
|
|
|
|
h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
|
|
|
|
h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
|
2017-11-16 11:26:00 +08:00
|
|
|
n = ah->parser_state;
|
2017-10-13 10:33:02 +08:00
|
|
|
if (n == 255) {
|
|
|
|
n = -1;
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->hdr_idx = (uint32_t)-1;
|
2014-10-12 08:38:16 +08:00
|
|
|
} else
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hdr_idx = 1;
|
|
|
|
} else {
|
2020-12-12 06:21:40 +00:00
|
|
|
n = lws_token_from_index(wsi, (int)h2n->hdr_idx, NULL,
|
2017-10-16 12:52:32 +08:00
|
|
|
NULL, NULL);
|
2019-11-05 21:00:45 +00:00
|
|
|
lwsl_header(" lws_tok_from_idx(%u) says %d\n",
|
|
|
|
(unsigned int)h2n->hdr_idx, n);
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (n == LWS_HPACK_IGNORE_ENTRY || n == -1)
|
|
|
|
h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
|
|
|
|
|
|
|
|
switch (h2n->hpack_type) {
|
|
|
|
/*
|
|
|
|
* hpack types with literal headers were parsed by the lws
|
|
|
|
* header SM... on recognition of a known lws header, it does
|
|
|
|
* the correct lws_frag_start() for us already. Other types
|
|
|
|
* (ie, indexed header) need us to do it here.
|
|
|
|
*/
|
|
|
|
case HPKT_LITERAL_HDR_VALUE_INCR:
|
|
|
|
case HPKT_LITERAL_HDR_VALUE:
|
|
|
|
case HPKT_LITERAL_HDR_VALUE_NEVER:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (n != -1 && n != LWS_HPACK_IGNORE_ENTRY &&
|
|
|
|
lws_frag_start(wsi, n)) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_header("%s: frag start failed\n",
|
|
|
|
__func__);
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
case HPKS_HLEN_EXT:
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->hpack_len = (uint32_t)((unsigned int)h2n->hpack_len |
|
|
|
|
(unsigned int)((c & 0x7f) << h2n->ext_count));
|
|
|
|
h2n->ext_count = (uint8_t)(h2n->ext_count + 7);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (c & 0x80) /* extended integer not complete yet */
|
|
|
|
break;
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hpack_len += h2n->hpack_m;
|
|
|
|
goto pre_data;
|
2014-10-09 16:57:47 +08:00
|
|
|
|
|
|
|
case HPKS_DATA:
|
2017-10-13 10:33:02 +08:00
|
|
|
//lwsl_header(" 0x%02X huff %d\n", c, h2n->huff);
|
|
|
|
c1 = c;
|
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
for (n = 0; n < 8; n++) {
|
2017-10-13 10:33:02 +08:00
|
|
|
if (h2n->huff) {
|
|
|
|
char b = (c >> 7) & 1;
|
|
|
|
prev = h2n->hpack_pos;
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->hpack_pos = (uint16_t)huftable_decode(
|
|
|
|
(int)h2n->hpack_pos, b);
|
|
|
|
c = (unsigned char)(c << 1);
|
2017-10-13 10:33:02 +08:00
|
|
|
if (h2n->hpack_pos == 0xffff) {
|
|
|
|
lwsl_notice("Huffman err\n");
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
if (!(h2n->hpack_pos & 0x8000)) {
|
|
|
|
if (!b)
|
|
|
|
h2n->zero_huff_padding = 1;
|
|
|
|
h2n->huff_pad++;
|
2014-10-12 08:38:16 +08:00
|
|
|
continue;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2020-12-12 06:21:40 +00:00
|
|
|
c1 = (uint8_t)(h2n->hpack_pos & 0x7fff);
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->hpack_pos = 0;
|
|
|
|
h2n->huff_pad = 0;
|
|
|
|
h2n->zero_huff_padding = 0;
|
|
|
|
|
|
|
|
/* EOS |11111111|11111111|11111111|111111 */
|
|
|
|
if (!c1 && prev == HUFTABLE_0x100_PREV) {
|
|
|
|
lws_h2_goaway(nwsi,
|
|
|
|
H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"Huffman EOT seen");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else
|
2014-10-12 08:38:16 +08:00
|
|
|
n = 8;
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (h2n->value) { /* value */
|
|
|
|
|
|
|
|
if (h2n->hdr_idx &&
|
|
|
|
h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY) {
|
|
|
|
|
2017-10-16 12:52:32 +08:00
|
|
|
if (ah->hdr_token_idx ==
|
|
|
|
WSI_TOKEN_HTTP_COLON_PATH) {
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2017-10-16 12:52:32 +08:00
|
|
|
switch (lws_parse_urldecode(
|
|
|
|
wsi, &c1)) {
|
2017-10-13 10:33:02 +08:00
|
|
|
case LPUR_CONTINUE:
|
|
|
|
break;
|
|
|
|
case LPUR_SWALLOW:
|
|
|
|
goto swallow;
|
|
|
|
case LPUR_EXCESSIVE:
|
|
|
|
case LPUR_FORBID:
|
|
|
|
lws_h2_goaway(nwsi,
|
2017-10-16 12:52:32 +08:00
|
|
|
H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Evil URI");
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lws_frag_append(wsi, c1)) {
|
2018-11-23 08:47:56 +08:00
|
|
|
lwsl_notice(
|
|
|
|
"%s: frag app fail\n",
|
2017-10-16 12:52:32 +08:00
|
|
|
__func__);
|
2016-04-10 09:33:54 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2017-10-16 12:52:32 +08:00
|
|
|
} //else
|
|
|
|
//lwsl_header("ignoring %c\n", c1);
|
2017-10-13 10:33:02 +08:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Convert name using existing parser,
|
|
|
|
* If h2n->unknown_header == 0, result is
|
2017-11-16 11:26:00 +08:00
|
|
|
* in wsi->parser_state
|
2017-10-13 10:33:02 +08:00
|
|
|
* using WSI_TOKEN_GET_URI.
|
|
|
|
*
|
|
|
|
* If unknown header h2n->unknown_header
|
|
|
|
* will be set.
|
|
|
|
*/
|
|
|
|
h2n->hpack_hdr_len++;
|
|
|
|
if (h2n->is_first_header_char) {
|
|
|
|
h2n->is_first_header_char = 0;
|
2020-12-12 06:21:40 +00:00
|
|
|
h2n->first_hdr_char = (char)c1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
lwsl_header("parser: %c\n", c1);
|
|
|
|
/* uppercase header names illegal */
|
|
|
|
if (c1 >= 'A' && c1 <= 'Z') {
|
|
|
|
lws_h2_goaway(nwsi,
|
|
|
|
H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"Uppercase literal hpack hdr");
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
2018-03-07 18:15:17 +08:00
|
|
|
plen = 1;
|
|
|
|
if (!h2n->unknown_header &&
|
|
|
|
lws_parse(wsi, &c1, &plen))
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->unknown_header = 1;
|
|
|
|
}
|
|
|
|
swallow:
|
|
|
|
(void)n;
|
|
|
|
} // for n
|
|
|
|
|
|
|
|
if (--h2n->hpack_len)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The header (h2n->value = 0) or the payload (h2n->value = 1)
|
|
|
|
* is complete.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (h2n->huff && (h2n->huff_pad > 7 ||
|
|
|
|
(h2n->zero_huff_padding && h2n->huff_pad))) {
|
2018-04-26 15:27:02 +08:00
|
|
|
lwsl_info("zero_huff_padding: %d huff_pad: %d\n",
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->zero_huff_padding, h2n->huff_pad);
|
|
|
|
lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
|
|
|
|
"Huffman padding excessive or wrong");
|
|
|
|
return 1;
|
|
|
|
}
|
2019-10-10 16:37:38 +01:00
|
|
|
fin:
|
2017-10-13 10:33:02 +08:00
|
|
|
if (!h2n->value && (
|
|
|
|
h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
|
|
|
|
h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
|
|
|
|
h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER)) {
|
|
|
|
h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
|
2017-11-16 11:26:00 +08:00
|
|
|
lwsl_header("wsi->parser_state: %d\n",
|
|
|
|
ah->parser_state);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2017-11-16 11:26:00 +08:00
|
|
|
if (ah->parser_state == WSI_TOKEN_NAME_PART) {
|
2017-10-13 10:33:02 +08:00
|
|
|
/* h2 headers come without the colon */
|
2018-03-07 18:15:17 +08:00
|
|
|
c1 = ':';
|
|
|
|
plen = 1;
|
|
|
|
n = lws_parse(wsi, &c1, &plen);
|
2017-10-13 10:33:02 +08:00
|
|
|
(void)n;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
|
2017-11-16 11:26:00 +08:00
|
|
|
if (ah->parser_state == WSI_TOKEN_NAME_PART ||
|
2019-02-26 17:18:24 +08:00
|
|
|
#if defined(LWS_WITH_CUSTOM_HEADERS)
|
|
|
|
ah->parser_state == WSI_TOKEN_UNKNOWN_VALUE_PART ||
|
|
|
|
#endif
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->parser_state == WSI_TOKEN_SKIPPING) {
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->unknown_header = 1;
|
2020-12-12 06:21:40 +00:00
|
|
|
ah->parser_state = 0xff;
|
2017-11-10 08:56:44 +08:00
|
|
|
wsi->seen_nonpseudoheader = 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we have the header */
|
|
|
|
if (!h2n->value) {
|
|
|
|
h2n->value = 1;
|
|
|
|
h2n->hpack = HPKS_HLEN;
|
|
|
|
h2n->huff_pad = 0;
|
|
|
|
h2n->zero_huff_padding = 0;
|
|
|
|
h2n->ext_count = 0;
|
|
|
|
break;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* we have got both the header and value
|
|
|
|
*/
|
|
|
|
|
2017-11-10 08:56:44 +08:00
|
|
|
m = -1;
|
2017-10-13 10:33:02 +08:00
|
|
|
switch (h2n->hpack_type) {
|
|
|
|
/*
|
|
|
|
* These are the only two that insert to the dyntable
|
|
|
|
*/
|
|
|
|
/* NEW indexed hdr with value */
|
|
|
|
case HPKT_INDEXED_HDR_6_VALUE_INCR:
|
|
|
|
/* header length is determined by known index */
|
2020-12-12 06:21:40 +00:00
|
|
|
m = lws_token_from_index(wsi, (int)h2n->hdr_idx, NULL, NULL,
|
2017-10-13 10:33:02 +08:00
|
|
|
&h2n->hpack_hdr_len);
|
2020-08-14 08:56:19 +01:00
|
|
|
if (m < 0)
|
|
|
|
/*
|
|
|
|
* The peer may only send known 6-bit indexes,
|
|
|
|
* there's still the possibility it sends an unset
|
|
|
|
* dynamic index that we can't succeed to look up
|
|
|
|
*/
|
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
goto add_it;
|
|
|
|
/* NEW literal hdr with value */
|
|
|
|
case HPKT_LITERAL_HDR_VALUE_INCR:
|
|
|
|
/*
|
|
|
|
* hdr is a new literal, so length is already in
|
|
|
|
* h2n->hpack_hdr_len
|
|
|
|
*/
|
2017-11-16 11:26:00 +08:00
|
|
|
m = ah->parser_state;
|
2017-10-13 10:33:02 +08:00
|
|
|
if (h2n->unknown_header ||
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->parser_state == WSI_TOKEN_NAME_PART ||
|
|
|
|
ah->parser_state == WSI_TOKEN_SKIPPING) {
|
2017-10-13 10:33:02 +08:00
|
|
|
if (h2n->first_hdr_char == ':') {
|
2017-10-16 12:52:32 +08:00
|
|
|
lwsl_info("HPKT_LITERAL_HDR_VALUE_INCR:"
|
|
|
|
" end state %d unk hdr %d\n",
|
2017-11-16 11:26:00 +08:00
|
|
|
ah->parser_state,
|
2017-10-13 10:33:02 +08:00
|
|
|
h2n->unknown_header);
|
|
|
|
/* unknown pseudoheaders are illegal */
|
|
|
|
lws_h2_goaway(nwsi,
|
|
|
|
H2_ERR_PROTOCOL_ERROR,
|
|
|
|
"Unknown pseudoheader");
|
2014-10-18 12:23:05 +08:00
|
|
|
return 1;
|
2017-10-13 10:33:02 +08:00
|
|
|
}
|
|
|
|
m = LWS_HPACK_IGNORE_ENTRY;
|
2014-10-18 12:23:05 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
add_it:
|
|
|
|
/*
|
|
|
|
* mark us as having been set at the time of dynamic
|
|
|
|
* token insertion.
|
|
|
|
*/
|
|
|
|
ah->frags[ah->nfrag].flags |= 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
if (lws_dynamic_token_insert(wsi, (int)h2n->hpack_hdr_len, m,
|
2017-10-13 10:33:02 +08:00
|
|
|
&ah->data[ah->frags[ah->nfrag].offset],
|
|
|
|
ah->frags[ah->nfrag].len)) {
|
|
|
|
lwsl_notice("%s: tok_insert fail\n", __func__);
|
|
|
|
return 1;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY && lws_frag_end(wsi))
|
|
|
|
return 1;
|
|
|
|
|
2017-11-10 08:56:44 +08:00
|
|
|
if (h2n->hpack_type != HPKT_INDEXED_HDR_6_VALUE_INCR) {
|
|
|
|
|
|
|
|
if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
|
|
|
|
h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
|
|
|
|
h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
|
2017-11-16 11:26:00 +08:00
|
|
|
m = ah->parser_state;
|
2017-11-10 08:56:44 +08:00
|
|
|
if (m == 255)
|
|
|
|
m = -1;
|
2017-11-16 11:26:00 +08:00
|
|
|
} else
|
2020-12-12 06:21:40 +00:00
|
|
|
m = lws_token_from_index(wsi, (int)h2n->hdr_idx,
|
2017-11-16 11:26:00 +08:00
|
|
|
NULL, NULL, NULL);
|
2017-11-10 08:56:44 +08:00
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (m != -1 && m != LWS_HPACK_IGNORE_ENTRY)
|
|
|
|
lws_dump_header(wsi, m);
|
|
|
|
|
2017-11-10 08:56:44 +08:00
|
|
|
if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
|
2017-10-13 10:33:02 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
h2n->is_first_header_char = 1;
|
|
|
|
h2n->hpack = HPKS_TYPE;
|
2014-10-18 12:23:05 +08:00
|
|
|
break;
|
2014-10-09 16:57:47 +08:00
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
return 0;
|
2014-10-09 16:57:47 +08:00
|
|
|
}
|
2014-10-12 14:31:47 +08:00
|
|
|
|
2017-11-10 08:56:44 +08:00
|
|
|
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
static unsigned int
|
2017-10-13 10:33:02 +08:00
|
|
|
lws_h2_num_start(int starting_bits, unsigned long num)
|
2014-10-12 14:31:47 +08:00
|
|
|
{
|
2020-12-12 06:21:40 +00:00
|
|
|
unsigned int mask = (unsigned int)((1 << starting_bits) - 1);
|
2014-10-12 14:31:47 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
if (num < mask)
|
2020-12-12 06:21:40 +00:00
|
|
|
return (unsigned int)num;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
lws_h2_num(int starting_bits, unsigned long num,
|
|
|
|
unsigned char **p, unsigned char *end)
|
|
|
|
{
|
2020-12-12 06:21:40 +00:00
|
|
|
unsigned int mask = (unsigned int)((1 << starting_bits) - 1);
|
2017-10-13 10:33:02 +08:00
|
|
|
|
|
|
|
if (num < mask)
|
|
|
|
return 0;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
num -= mask;
|
2017-10-13 10:33:02 +08:00
|
|
|
do {
|
|
|
|
if (num > 127)
|
2020-12-12 06:21:40 +00:00
|
|
|
*((*p)++) = (uint8_t)(0x80 | (num & 0x7f));
|
2017-10-13 10:33:02 +08:00
|
|
|
else
|
2020-12-12 06:21:40 +00:00
|
|
|
*((*p)++) = (uint8_t)(0x00 | (num & 0x7f));
|
2014-10-12 14:31:47 +08:00
|
|
|
if (*p >= end)
|
|
|
|
return 1;
|
|
|
|
num >>= 7;
|
2017-10-13 10:33:02 +08:00
|
|
|
} while (num);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name,
|
2015-12-06 10:05:37 +08:00
|
|
|
const unsigned char *value, int length,
|
|
|
|
unsigned char **p, unsigned char *end)
|
2014-10-12 14:31:47 +08:00
|
|
|
{
|
|
|
|
int len;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2020-08-03 15:52:50 +01:00
|
|
|
#if defined(_DEBUG)
|
|
|
|
/* value does not have to be NUL-terminated... %.*s not available on
|
|
|
|
* all platforms */
|
2021-07-05 16:41:41 +08:00
|
|
|
if (value) {
|
|
|
|
lws_strnncpy((char *)*p, (const char *)value, length,
|
|
|
|
lws_ptr_diff(end, (*p)));
|
|
|
|
|
|
|
|
lwsl_header("%s: %p %s:%s (len %d)\n", __func__, *p, name,
|
|
|
|
(const char *)*p, length);
|
|
|
|
} else {
|
|
|
|
lwsl_err("%s: %p dummy copy %s (len %d)\n", __func__, *p, name, length);
|
|
|
|
}
|
2020-08-03 15:52:50 +01:00
|
|
|
#endif
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-10-25 08:00:23 +08:00
|
|
|
len = (int)strlen((char *)name);
|
2014-10-12 14:31:47 +08:00
|
|
|
if (len)
|
|
|
|
if (name[len - 1] == ':')
|
|
|
|
len--;
|
|
|
|
|
2019-12-23 11:31:57 +00:00
|
|
|
if (wsi->mux_substream && !strncmp((const char *)name,
|
2020-12-12 06:21:40 +00:00
|
|
|
"transfer-encoding", (unsigned int)len)) {
|
2017-10-13 10:33:02 +08:00
|
|
|
lwsl_header("rejecting %s\n", name);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
if (end - *p < len + length + 8)
|
|
|
|
return 1;
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
*((*p)++) = 0; /* literal hdr, literal name, */
|
2014-10-12 14:31:47 +08:00
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
*((*p)++) = (uint8_t)(0 | (uint8_t)lws_h2_num_start(7, (unsigned long)len)); /* non-HUF */
|
2020-12-12 06:21:40 +00:00
|
|
|
if (lws_h2_num(7, (unsigned long)len, p, end))
|
2014-10-12 14:31:47 +08:00
|
|
|
return 1;
|
2018-08-24 14:43:50 +08:00
|
|
|
|
|
|
|
/* upper-case header names are verboten in h2, but OK on h1, so
|
|
|
|
* they're not illegal per se. Silently convert them for h2... */
|
|
|
|
|
|
|
|
while(len--)
|
2020-12-12 06:21:40 +00:00
|
|
|
*((*p)++) = (uint8_t)tolower((int)*name++);
|
2014-10-12 14:31:47 +08:00
|
|
|
|
2021-01-06 15:08:22 +00:00
|
|
|
*((*p)++) = (uint8_t)(0 | (uint8_t)lws_h2_num_start(7, (unsigned long)length)); /* non-HUF */
|
2020-12-12 06:21:40 +00:00
|
|
|
if (lws_h2_num(7, (unsigned long)length, p, end))
|
2014-10-12 14:31:47 +08:00
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2021-07-05 16:41:41 +08:00
|
|
|
if (value)
|
|
|
|
memcpy(*p, value, (unsigned int)length);
|
2014-10-12 14:31:47 +08:00
|
|
|
*p += length;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token,
|
2015-12-06 10:05:37 +08:00
|
|
|
const unsigned char *value, int length,
|
|
|
|
unsigned char **p, unsigned char *end)
|
2014-10-12 14:31:47 +08:00
|
|
|
{
|
|
|
|
const unsigned char *name;
|
|
|
|
|
|
|
|
name = lws_token_to_string(token);
|
|
|
|
if (!name)
|
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
return lws_add_http2_header_by_name(wsi, name, value, length, p, end);
|
2014-10-12 14:31:47 +08:00
|
|
|
}
|
|
|
|
|
2017-10-13 10:33:02 +08:00
|
|
|
int lws_add_http2_header_status(struct lws *wsi, unsigned int code,
|
|
|
|
unsigned char **p, unsigned char *end)
|
2014-10-12 14:31:47 +08:00
|
|
|
{
|
|
|
|
unsigned char status[10];
|
|
|
|
int n;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2017-12-01 11:09:32 +08:00
|
|
|
wsi->h2.send_END_STREAM = 0; // !!(code >= 400);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
n = sprintf((char *)status, "%u", code);
|
2015-12-16 18:19:08 +08:00
|
|
|
if (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,
|
|
|
|
status, n, p, end))
|
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
2014-12-04 23:59:35 +01:00
|
|
|
}
|