2014-10-12 08:38:16 +08:00
|
|
|
/*
|
|
|
|
* lib/hpack.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Andy Green <andy@warmcat.com>
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "private-libwebsockets.h"
|
|
|
|
|
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 | |
|
|
|
|
+-------+-----------------------------+---------------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
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_hpack_update_table_size(struct lws *wsi, int idx)
|
2014-10-09 16:57:47 +08:00
|
|
|
{
|
2014-10-12 08:38:16 +08:00
|
|
|
lwsl_info("hpack set table size %d\n", idx);
|
|
|
|
return 0;
|
2014-10-09 16:57:47 +08:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2014-10-12 08:38:16 +08:00
|
|
|
struct allocated_headers * ah = wsi->u.http2.http.ah;
|
|
|
|
|
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
|
|
|
|
2016-04-10 09:33:54 +08:00
|
|
|
if (ah->nfrag >= ARRAY_SIZE(ah->frag_index)) {
|
|
|
|
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
|
|
|
|
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;
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2015-12-15 21:15:58 +08:00
|
|
|
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
|
|
|
{
|
|
|
|
struct allocated_headers * ah = wsi->u.http2.http.ah;
|
|
|
|
|
|
|
|
ah->data[ah->pos++] = c;
|
2015-12-15 21:15:58 +08:00
|
|
|
ah->frags[ah->nfrag].len++;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2015-12-25 12:44:12 +08:00
|
|
|
return ah->pos >= wsi->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
|
|
|
{
|
|
|
|
if (lws_frag_append(wsi, 0))
|
|
|
|
return 1;
|
|
|
|
|
2015-12-15 21:15:58 +08:00
|
|
|
wsi->u.http2.http.ah->nfrag++;
|
2014-10-12 08:38:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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];
|
|
|
|
int len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
|
|
|
|
s[len] = '\0';
|
2014-10-18 12:23:05 +08:00
|
|
|
lwsl_info(" hdr tok %d (%s) = '%s'\n", hdr, lws_token_to_string(hdr), s);
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
|
|
|
|
2015-12-06 10:05:37 +08:00
|
|
|
static int
|
|
|
|
lws_token_from_index(struct lws *wsi, int index, char **arg, int *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
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
/* dynamic table only belongs to network wsi */
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
wsi = lws_http2_get_network_wsi(wsi);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
dyn = wsi->u.http2.hpack_dyn_table;
|
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
if (index < ARRAY_SIZE(static_token))
|
|
|
|
return static_token[index];
|
2014-10-18 12:23:05 +08:00
|
|
|
|
|
|
|
if (!dyn)
|
|
|
|
return 0;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
index -= ARRAY_SIZE(static_token);
|
|
|
|
if (index >= dyn->num_entries)
|
|
|
|
return 0;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
if (arg && len) {
|
|
|
|
*arg = dyn->args + dyn->entries[index].arg_offset;
|
|
|
|
*len = dyn->entries[index].arg_len;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
return dyn->entries[index].token;
|
|
|
|
}
|
|
|
|
|
2015-12-06 10:05:37 +08:00
|
|
|
static int
|
|
|
|
lws_hpack_add_dynamic_header(struct lws *wsi, int token, char *arg, int len)
|
2014-10-18 12:23:05 +08:00
|
|
|
{
|
|
|
|
struct hpack_dynamic_table *dyn;
|
|
|
|
int ret = 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
wsi = lws_http2_get_network_wsi(wsi);
|
|
|
|
dyn = wsi->u.http2.hpack_dyn_table;
|
|
|
|
|
|
|
|
if (!dyn) {
|
2014-12-04 23:59:35 +01:00
|
|
|
dyn = lws_zalloc(sizeof(*dyn));
|
2014-10-18 12:23:05 +08:00
|
|
|
if (!dyn)
|
|
|
|
return 1;
|
|
|
|
wsi->u.http2.hpack_dyn_table = dyn;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-12-04 23:59:35 +01:00
|
|
|
dyn->args = lws_malloc(1024);
|
2014-10-18 12:23:05 +08:00
|
|
|
if (!dyn->args)
|
|
|
|
goto bail1;
|
|
|
|
dyn->args_length = 1024;
|
2014-12-04 23:59:35 +01:00
|
|
|
dyn->entries = lws_malloc(sizeof(dyn->entries[0]) * 20);
|
2014-10-18 12:23:05 +08:00
|
|
|
if (!dyn->entries)
|
|
|
|
goto bail2;
|
|
|
|
dyn->num_entries = 20;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
if (dyn->next == dyn->num_entries)
|
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
if (dyn->args_length - dyn->pos < len)
|
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
dyn->entries[dyn->next].token = token;
|
|
|
|
dyn->entries[dyn->next].arg_offset = dyn->pos;
|
|
|
|
if (len)
|
|
|
|
memcpy(dyn->args + dyn->pos, arg, len);
|
|
|
|
dyn->entries[dyn->next].arg_len = len;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2015-12-06 10:05:37 +08:00
|
|
|
lwsl_info("%s: added dynamic hdr %d, token %d (%s), len %d\n",
|
|
|
|
__func__, dyn->next, token, lws_token_to_string(token), len);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
dyn->pos += len;
|
|
|
|
dyn->next++;
|
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
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
bail2:
|
2014-12-04 23:59:35 +01:00
|
|
|
lws_free(dyn->args);
|
2014-10-18 12:23:05 +08:00
|
|
|
bail1:
|
2014-12-04 23:59:35 +01:00
|
|
|
lws_free(dyn);
|
2014-10-18 12:23:05 +08:00
|
|
|
wsi->u.http2.hpack_dyn_table = NULL;
|
2014-12-04 23:59:35 +01:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
return ret;
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
|
|
|
|
2015-12-04 11:08:32 +08:00
|
|
|
static int lws_write_indexed_hdr(struct lws *wsi, int idx)
|
2014-10-12 08:38:16 +08:00
|
|
|
{
|
|
|
|
const char *p;
|
2014-10-18 12:23:05 +08:00
|
|
|
int tok = lws_token_from_index(wsi, idx, NULL, 0);
|
2014-10-12 08:38:16 +08:00
|
|
|
|
2015-12-06 10:05:37 +08:00
|
|
|
lwsl_info("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
|
|
|
|
lws_token_to_string(tok));
|
2014-10-12 08:38:16 +08:00
|
|
|
|
|
|
|
if (lws_frag_start(wsi, tok))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (idx < ARRAY_SIZE(http2_canned)) {
|
|
|
|
p = http2_canned[idx];
|
|
|
|
while (*p)
|
|
|
|
if (lws_frag_append(wsi, *p++))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
unsigned int prev;
|
|
|
|
unsigned char c1;
|
|
|
|
int n;
|
|
|
|
|
2016-04-10 09:33:54 +08:00
|
|
|
lwsl_debug(" state %d\n", wsi->u.http2.hpack);
|
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
switch (wsi->u.http2.hpack) {
|
2014-10-18 12:23:05 +08:00
|
|
|
case HPKS_OPT_PADDING:
|
|
|
|
wsi->u.http2.padding = c;
|
|
|
|
lwsl_info("padding %d\n", c);
|
|
|
|
if (wsi->u.http2.flags & LWS_HTTP2_FLAG_PRIORITY) {
|
|
|
|
wsi->u.http2.hpack = HKPS_OPT_E_DEPENDENCY;
|
|
|
|
wsi->u.http2.hpack_m = 4;
|
|
|
|
} else
|
|
|
|
wsi->u.http2.hpack = HPKS_TYPE;
|
|
|
|
break;
|
|
|
|
case HKPS_OPT_E_DEPENDENCY:
|
|
|
|
wsi->u.http2.hpack_e_dep <<= 8;
|
|
|
|
wsi->u.http2.hpack_e_dep |= c;
|
|
|
|
if (! --wsi->u.http2.hpack_m) {
|
|
|
|
lwsl_info("hpack_e_dep = 0x%x\n", wsi->u.http2.hpack_e_dep);
|
|
|
|
wsi->u.http2.hpack = HKPS_OPT_WEIGHT;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case HKPS_OPT_WEIGHT:
|
|
|
|
/* weight */
|
|
|
|
wsi->u.http2.hpack = HPKS_TYPE;
|
|
|
|
break;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
case HPKS_TYPE:
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-27 16:46:44 +08:00
|
|
|
if (wsi->u.http2.count > (wsi->u.http2.length - wsi->u.http2.padding)) {
|
|
|
|
lwsl_info("padding eat\n");
|
|
|
|
break;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
if (c & 0x80) { /* indexed header field only */
|
2014-10-12 08:38:16 +08:00
|
|
|
/* just a possibly-extended integer */
|
|
|
|
wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_7;
|
2016-04-10 09:33:54 +08:00
|
|
|
lwsl_debug("HKPS_TYPE setting header_index %d\n", c & 0x7f);
|
2014-10-09 16:57:47 +08:00
|
|
|
wsi->u.http2.header_index = c & 0x7f;
|
2014-10-12 08:38:16 +08:00
|
|
|
if ((c & 0x7f) == 0x7f) {
|
|
|
|
wsi->u.http2.hpack_len = c & 0x7f;
|
|
|
|
wsi->u.http2.hpack_m = 0;
|
|
|
|
wsi->u.http2.hpack = HPKS_IDX_EXT;
|
|
|
|
break;
|
|
|
|
}
|
2016-04-10 09:33:54 +08:00
|
|
|
lwsl_debug("HKPS_TYPE: %d\n", c & 0x7f);
|
2014-10-18 12:23:05 +08:00
|
|
|
if (lws_write_indexed_hdr(wsi, c & 0x7f))
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2014-10-09 16:57:47 +08:00
|
|
|
/* stay at same state */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (c & 0x40) { /* literal header incr idx */
|
2014-10-12 08:38:16 +08:00
|
|
|
/*
|
|
|
|
* [possibly-extended hdr idx (6) | new literal hdr name]
|
|
|
|
* H + possibly-extended value length
|
|
|
|
* literal value
|
|
|
|
*/
|
2016-04-10 09:33:54 +08:00
|
|
|
lwsl_debug("HKPS_TYPE 2 setting header_index %d\n", 0);
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.header_index = 0;
|
2014-10-09 16:57:47 +08:00
|
|
|
if (c == 0x40) { /* literal name */
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
|
|
|
|
wsi->u.http2.value = 0;
|
2014-10-09 16:57:47 +08:00
|
|
|
wsi->u.http2.hpack = HPKS_HLEN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* indexed name */
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
|
|
|
|
if ((c & 0x3f) == 0x3f) {
|
|
|
|
wsi->u.http2.hpack_len = c & 0x3f;
|
|
|
|
wsi->u.http2.hpack_m = 0;
|
|
|
|
wsi->u.http2.hpack = HPKS_IDX_EXT;
|
|
|
|
break;
|
|
|
|
}
|
2016-04-10 09:33:54 +08:00
|
|
|
lwsl_debug("HKPS_TYPE 3 setting header_index %d\n", c & 0x3f);
|
2014-10-09 16:57:47 +08:00
|
|
|
wsi->u.http2.header_index = c & 0x3f;
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.value = 1;
|
2014-10-09 16:57:47 +08:00
|
|
|
wsi->u.http2.hpack = HPKS_HLEN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch(c & 0xf0) {
|
2014-10-12 08:38:16 +08:00
|
|
|
case 0x10: /* literal header never index */
|
2014-10-09 16:57:47 +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 */
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE;
|
|
|
|
wsi->u.http2.hpack = HPKS_HLEN;
|
|
|
|
wsi->u.http2.value = 0;
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-04-10 09:33:54 +08:00
|
|
|
//lwsl_debug("indexed\n");
|
2014-10-09 16:57:47 +08:00
|
|
|
/* indexed name */
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_4_VALUE;
|
|
|
|
wsi->u.http2.header_index = 0;
|
|
|
|
if ((c & 0xf) == 0xf) {
|
|
|
|
wsi->u.http2.hpack_len = c & 0xf;
|
|
|
|
wsi->u.http2.hpack_m = 0;
|
|
|
|
wsi->u.http2.hpack = HPKS_IDX_EXT;
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-04-10 09:33:54 +08:00
|
|
|
//lwsl_err("HKPS_TYPE 5 setting header_index %d\n", c & 0xf);
|
2014-10-09 16:57:47 +08:00
|
|
|
wsi->u.http2.header_index = c & 0xf;
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.value = 1;
|
|
|
|
wsi->u.http2.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) */
|
|
|
|
wsi->u.http2.hpack_type = HPKT_SIZE_5;
|
|
|
|
if ((c & 0x1f) == 0x1f) {
|
|
|
|
wsi->u.http2.hpack_len = c & 0x1f;
|
|
|
|
wsi->u.http2.hpack_m = 0;
|
|
|
|
wsi->u.http2.hpack = HPKS_IDX_EXT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lws_hpack_update_table_size(wsi, c & 0x1f);
|
|
|
|
/* stay at HPKS_TYPE state */
|
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:
|
|
|
|
wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m;
|
|
|
|
wsi->u.http2.hpack_m += 7;
|
|
|
|
if (!(c & 0x80)) {
|
|
|
|
switch (wsi->u.http2.hpack_type) {
|
|
|
|
case HPKT_INDEXED_HDR_7:
|
2016-04-10 09:33:54 +08:00
|
|
|
//lwsl_err("HKPS_IDX_EXT hdr idx %d\n", wsi->u.http2.hpack_len);
|
2014-10-18 12:23:05 +08:00
|
|
|
if (lws_write_indexed_hdr(wsi, wsi->u.http2.hpack_len))
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
|
|
|
wsi->u.http2.hpack = HPKS_TYPE;
|
|
|
|
break;
|
|
|
|
default:
|
2016-04-10 09:33:54 +08:00
|
|
|
// lwsl_err("HKPS_IDX_EXT setting header_index %d\n",
|
|
|
|
// wsi->u.http2.hpack_len);
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.header_index = wsi->u.http2.hpack_len;
|
|
|
|
wsi->u.http2.value = 1;
|
|
|
|
wsi->u.http2.hpack = HPKS_HLEN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case HPKS_HLEN: /* [ H | 7+ ] */
|
2014-10-09 16:57:47 +08:00
|
|
|
wsi->u.http2.huff = !!(c & 0x80);
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.hpack_pos = 0;
|
2014-10-09 16:57:47 +08:00
|
|
|
wsi->u.http2.hpack_len = c & 0x7f;
|
2014-10-12 08:38:16 +08:00
|
|
|
if (wsi->u.http2.hpack_len < 0x7f) {
|
|
|
|
pre_data:
|
|
|
|
if (wsi->u.http2.value) {
|
2016-04-10 09:33:54 +08:00
|
|
|
if (wsi->u.http2.header_index)
|
2015-12-06 10:05:37 +08:00
|
|
|
if (lws_frag_start(wsi, lws_token_from_index(wsi,
|
|
|
|
wsi->u.http2.header_index,
|
2016-04-10 09:33:54 +08:00
|
|
|
NULL, NULL))) {
|
|
|
|
// lwsl_notice("%s: hlen failed\n", __func__);
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2016-04-10 09:33:54 +08:00
|
|
|
}
|
2014-10-12 08:38:16 +08:00
|
|
|
} else
|
|
|
|
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
|
|
|
|
wsi->u.http2.hpack = HPKS_DATA;
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
wsi->u.http2.hpack_m = 0;
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.hpack = HPKS_HLEN_EXT;
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
case HPKS_HLEN_EXT:
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.hpack_len += (c & 0x7f) <<
|
|
|
|
wsi->u.http2.hpack_m;
|
2014-10-09 16:57:47 +08:00
|
|
|
wsi->u.http2.hpack_m += 7;
|
|
|
|
if (!(c & 0x80))
|
2014-10-12 08:38:16 +08:00
|
|
|
goto pre_data;
|
|
|
|
|
2014-10-09 16:57:47 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case HPKS_DATA:
|
2014-10-12 08:38:16 +08:00
|
|
|
for (n = 0; n < 8; n++) {
|
|
|
|
if (wsi->u.http2.huff) {
|
|
|
|
prev = wsi->u.http2.hpack_pos;
|
2015-12-06 10:05:37 +08:00
|
|
|
wsi->u.http2.hpack_pos = huftable_decode(
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.hpack_pos,
|
2015-12-06 10:05:37 +08:00
|
|
|
(c >> 7) & 1);
|
2014-10-12 08:38:16 +08:00
|
|
|
c <<= 1;
|
|
|
|
if (wsi->u.http2.hpack_pos == 0xffff)
|
|
|
|
return 1;
|
|
|
|
if (!(wsi->u.http2.hpack_pos & 0x8000))
|
|
|
|
continue;
|
|
|
|
c1 = wsi->u.http2.hpack_pos & 0x7fff;
|
|
|
|
wsi->u.http2.hpack_pos = 0;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
if (!c1 && prev == HUFTABLE_0x100_PREV)
|
|
|
|
; /* EOT */
|
|
|
|
} else {
|
|
|
|
n = 8;
|
|
|
|
c1 = c;
|
|
|
|
}
|
|
|
|
if (wsi->u.http2.value) { /* value */
|
2016-04-10 09:33:54 +08:00
|
|
|
if (wsi->u.http2.header_index)
|
|
|
|
if (lws_frag_append(wsi, c1))
|
|
|
|
return 1;
|
2014-10-12 08:38:16 +08:00
|
|
|
} else { /* name */
|
2015-12-15 21:15:58 +08:00
|
|
|
if (lws_parse(wsi, c1))
|
2014-10-12 08:38:16 +08:00
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (--wsi->u.http2.hpack_len == 0) {
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-18 12:23:05 +08:00
|
|
|
switch (wsi->u.http2.hpack_type) {
|
|
|
|
case HPKT_LITERAL_HDR_VALUE_INCR:
|
|
|
|
case HPKT_INDEXED_HDR_6_VALUE_INCR: // !!!
|
2015-12-06 10:05:37 +08:00
|
|
|
if (lws_hpack_add_dynamic_header(wsi,
|
|
|
|
lws_token_from_index(wsi,
|
|
|
|
wsi->u.http2.header_index,
|
|
|
|
NULL, NULL), NULL, 0))
|
2014-10-18 12:23:05 +08:00
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
n = 8;
|
|
|
|
if (wsi->u.http2.value) {
|
|
|
|
if (lws_frag_end(wsi))
|
|
|
|
return 1;
|
2016-04-10 09:33:54 +08:00
|
|
|
// lwsl_err("data\n");
|
2015-12-06 10:05:37 +08:00
|
|
|
lws_dump_header(wsi, lws_token_from_index(
|
|
|
|
wsi, wsi->u.http2.header_index,
|
|
|
|
NULL, NULL));
|
|
|
|
if (wsi->u.http2.count + wsi->u.http2.padding ==
|
|
|
|
wsi->u.http2.length)
|
2014-10-18 12:23:05 +08:00
|
|
|
wsi->u.http2.hpack = HKPS_OPT_DISCARD_PADDING;
|
|
|
|
else
|
|
|
|
wsi->u.http2.hpack = HPKS_TYPE;
|
2014-10-12 08:38:16 +08:00
|
|
|
} else { /* name */
|
2016-04-10 09:33:54 +08:00
|
|
|
//if (wsi->u.hdr.parser_state < WSI_TOKEN_COUNT)
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 08:38:16 +08:00
|
|
|
wsi->u.http2.value = 1;
|
|
|
|
wsi->u.http2.hpack = HPKS_HLEN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2014-10-18 12:23:05 +08:00
|
|
|
case HKPS_OPT_DISCARD_PADDING:
|
|
|
|
lwsl_info("eating padding %x\n", c);
|
|
|
|
if (! --wsi->u.http2.padding)
|
|
|
|
wsi->u.http2.hpack = HPKS_TYPE;
|
|
|
|
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
|
|
|
|
2015-12-06 09:15:27 +08:00
|
|
|
static int lws_http2_num(int starting_bits, unsigned long num,
|
|
|
|
unsigned char **p, unsigned char *end)
|
2014-10-12 14:31:47 +08:00
|
|
|
{
|
|
|
|
int mask = (1 << starting_bits) - 1;
|
|
|
|
|
|
|
|
if (num < mask) {
|
|
|
|
*((*p)++) |= num;
|
|
|
|
return *p >= end;
|
|
|
|
}
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
*((*p)++) |= mask;
|
|
|
|
if (*p >= end)
|
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
num -= mask;
|
|
|
|
while (num >= 128) {
|
|
|
|
*((*p)++) = 0x80 | (num & 0x7f);
|
|
|
|
if (*p >= end)
|
|
|
|
return 1;
|
|
|
|
num >>= 7;
|
|
|
|
}
|
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_name(struct lws *wsi,
|
2015-12-06 09:15:27 +08:00
|
|
|
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
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
lwsl_info("%s: %p %s:%s\n", __func__, *p, name, value);
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
len = strlen((char *)name);
|
|
|
|
if (len)
|
|
|
|
if (name[len - 1] == ':')
|
|
|
|
len--;
|
|
|
|
|
|
|
|
if (end - *p < len + length + 8)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
*((*p)++) = 0; /* not indexed, literal name */
|
|
|
|
|
|
|
|
**p = 0; /* non-HUF */
|
|
|
|
if (lws_http2_num(7, len, p, end))
|
|
|
|
return 1;
|
|
|
|
memcpy(*p, name, len);
|
|
|
|
*p += len;
|
|
|
|
|
|
|
|
*(*p) = 0; /* non-HUF */
|
|
|
|
if (lws_http2_num(7, length, p, end))
|
|
|
|
return 1;
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2014-10-12 14:31:47 +08:00
|
|
|
memcpy(*p, value, length);
|
|
|
|
*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
|
|
|
}
|
|
|
|
|
2015-12-16 18:19:08 +08:00
|
|
|
int lws_add_http2_header_status(struct lws *wsi,
|
2015-12-06 09:15:27 +08:00
|
|
|
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
|
|
|
|
2014-10-19 07:36:20 +08:00
|
|
|
wsi->u.http2.send_END_STREAM = !!(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
|
|
|
}
|