mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
http2 add hpack decode support
Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
parent
07631f49af
commit
ecc2e72ca1
6 changed files with 1066 additions and 342 deletions
239
lib/hpack.c
Normal file
239
lib/hpack.c
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* 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,
|
||||
WSI_TOKEN_HTTP_HOST,
|
||||
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,
|
||||
};
|
||||
|
||||
static const char * const http2_canned[] = {
|
||||
"",
|
||||
"",
|
||||
"GET",
|
||||
"POST",
|
||||
"/",
|
||||
"/index.html",
|
||||
"http",
|
||||
"https",
|
||||
"200",
|
||||
"204",
|
||||
"206",
|
||||
"300",
|
||||
"304",
|
||||
"400",
|
||||
"404",
|
||||
"500",
|
||||
"",
|
||||
"gzip, deflate"
|
||||
};
|
||||
|
||||
#include "huftable.h"
|
||||
|
||||
int lextable_decode(int pos, char c)
|
||||
{
|
||||
int q = pos + !!c;
|
||||
|
||||
if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */
|
||||
return lextable[q] | 0x8000;
|
||||
|
||||
return pos + (lextable[q] << 1);
|
||||
}
|
||||
|
||||
static int lws_add_header(int header, const char *payload, int len)
|
||||
{
|
||||
wsi->u.ah.frag_index[header]
|
||||
}
|
||||
|
||||
int lws_hpack_interpret(struct libwebsocket *wsi, unsigned char c)
|
||||
{
|
||||
switch (wsi->u.http2.hpack) {
|
||||
case HPKS_TYPE:
|
||||
if (c & 0x80) { /* indexed header field only */
|
||||
wsi->u.http2.header_index = c & 0x7f;
|
||||
/* stay at same state */
|
||||
break;
|
||||
}
|
||||
if (c & 0x40) { /* literal header incr idx */
|
||||
if (c == 0x40) { /* literal name */
|
||||
wsi->u.http2.header_index = 0;
|
||||
wsi->u.http2.hpack
|
||||
wsi->u.http2.hpack = HPKS_HLEN;
|
||||
break;
|
||||
}
|
||||
/* indexed name */
|
||||
wsi->u.http2.header_index = c & 0x3f;
|
||||
wsi->u.http2.hpack = HPKS_HLEN;
|
||||
break;
|
||||
}
|
||||
switch(c & 0xf0) {
|
||||
case 0: /* literal header without indexing */
|
||||
if (c == 0) { /* literal name */
|
||||
wsi->u.http2.hpack = HPKS_NAME_HLEN;
|
||||
break;
|
||||
}
|
||||
/* indexed name */
|
||||
wsi->u.http2.header_index = c & 0xf;
|
||||
wsi->u.http2.hpack = HPKS_VALUE_HLEN;
|
||||
break;
|
||||
case 0x10: /* literal header never indexed */
|
||||
if (c == 0x10) { /* literal name */
|
||||
wsi->u.http2.header_index = 0;
|
||||
wsi->u.http2.hpack = HPKS_NAME_HLEN;
|
||||
break;
|
||||
}
|
||||
/* indexed name */
|
||||
wsi->u.http2.header_index = c & 0xf;
|
||||
wsi->u.http2.hpack = HPKS_NAME_HLEN;
|
||||
break;
|
||||
case 0x20:
|
||||
case 0x30: /* header table size update */
|
||||
/* = c & 0x1f */
|
||||
/* stay at same state */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HPKS_HLEN:
|
||||
wsi->u.http2.huff = !!(c & 0x80);
|
||||
wsi->u.http2.hpack_len = c & 0x7f;
|
||||
if (wsi->u.http2.hpack_len < 127) {
|
||||
wsi->u.http2.hpack = HPKS_NAME_DATA;
|
||||
break;
|
||||
}
|
||||
wsi->u.http2.hpack_m = 0;
|
||||
wsi->u.http2.hpack = HPKS_NAME_HLEN_EXT;
|
||||
break;
|
||||
case HPKS_HLEN_EXT:
|
||||
wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m;
|
||||
wsi->u.http2.hpack_m += 7;
|
||||
if (!(c & 0x80))
|
||||
wsi->u.http2.hpack = HPKS_NAME_DATA;
|
||||
break;
|
||||
|
||||
case HPKS_DATA:
|
||||
|
||||
}
|
||||
}
|
22
lib/http2.c
22
lib/http2.c
|
@ -32,6 +32,7 @@ const struct http2_settings lws_http2_default_settings = { {
|
|||
/* LWS_HTTP2_SETTINGS__MAX_HEADER_LIST_SIZE */ ~0,
|
||||
}};
|
||||
|
||||
|
||||
void lws_http2_init(struct http2_settings *settings)
|
||||
{
|
||||
memcpy(settings, lws_http2_default_settings.setting, sizeof(*settings));
|
||||
|
@ -193,16 +194,20 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
case WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS:
|
||||
case WSI_STATE_HTTP2_ESTABLISHED:
|
||||
if (wsi->u.http2.frame_state == LWS_HTTP2_FRAME_HEADER_LENGTH) { // payload
|
||||
/* applies to wsi->u.http2.stream_wsi which may be wsi*/
|
||||
switch(wsi->u.http2.type) {
|
||||
case LWS_HTTP2_FRAME_TYPE_SETTINGS:
|
||||
wsi->u.http2.one_setting[wsi->u.http2.count % LWS_HTTP2_SETTINGS_LENGTH] = c;
|
||||
wsi->u.http2.stream_wsi->u.http2.one_setting[wsi->u.http2.count % LWS_HTTP2_SETTINGS_LENGTH] = c;
|
||||
if (wsi->u.http2.count % LWS_HTTP2_SETTINGS_LENGTH == LWS_HTTP2_SETTINGS_LENGTH - 1)
|
||||
if (lws_http2_interpret_settings_payload(
|
||||
&wsi->u.http2.peer_settings,
|
||||
&wsi->u.http2.stream_wsi->u.http2.peer_settings,
|
||||
wsi->u.http2.one_setting,
|
||||
LWS_HTTP2_SETTINGS_LENGTH))
|
||||
return 1;
|
||||
break;
|
||||
case LWS_HTTP2_FRAME_TYPE_HEADERS:
|
||||
|
||||
break;
|
||||
}
|
||||
wsi->u.http2.count++;
|
||||
if (wsi->u.http2.count == wsi->u.http2.length) {
|
||||
|
@ -238,6 +243,7 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
case 8:
|
||||
wsi->u.http2.stream_id <<= 8;
|
||||
wsi->u.http2.stream_id |= c;
|
||||
wsi->u.http2.stream_wsi = wsi;
|
||||
break;
|
||||
}
|
||||
if (wsi->u.http2.frame_state == LWS_HTTP2_FRAME_HEADER_LENGTH) { /* frame header complete */
|
||||
|
@ -258,10 +264,14 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
}
|
||||
break;
|
||||
case LWS_HTTP2_FRAME_TYPE_HEADERS:
|
||||
wsi_new = lws_http2_wsi_from_id(wsi, wsi->u.http2.stream_id);
|
||||
if (!wsi_new) {
|
||||
wsi_new = lws_create_server_child_wsi(context, wsi, wsi->u.http2.stream_id);
|
||||
}
|
||||
if (!wsi->u.http2.stream_id)
|
||||
return 1;
|
||||
wsi->u.http2.stream_wsi = lws_http2_wsi_from_id(wsi, wsi->u.http2.stream_id);
|
||||
if (!wsi->u.http2.stream_wsi)
|
||||
wsi->u.http2.stream_wsi = lws_create_server_child_wsi(context, wsi, wsi->u.http2.stream_id);
|
||||
|
||||
if (!wsi->u.http2.stream_wsi)
|
||||
return 1;
|
||||
}
|
||||
if (wsi->u.http2.length == 0)
|
||||
wsi->u.http2.frame_state = 0;
|
||||
|
|
1049
lib/lextable.h
1049
lib/lextable.h
File diff suppressed because it is too large
Load diff
|
@ -327,10 +327,48 @@ enum lws_token_indexes {
|
|||
WSI_TOKEN_VERSION,
|
||||
WSI_TOKEN_SWORIGIN,
|
||||
|
||||
WSI_TOKEN_HTTP_COLON_AUTHORITY,
|
||||
WSI_TOKEN_HTTP_COLON_METHOD,
|
||||
WSI_TOKEN_HTTP_COLON_PATH,
|
||||
WSI_TOKEN_HTTP_COLON_SCHEME,
|
||||
WSI_TOKEN_HTTP_COLON_STATUS,
|
||||
|
||||
WSI_TOKEN_HTTP_ACCEPT_CHARSET,
|
||||
WSI_TOKEN_HTTP_ACCEPT_RANGES,
|
||||
WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||
WSI_TOKEN_HTTP_AGE,
|
||||
WSI_TOKEN_HTTP_ALLOW,
|
||||
WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
|
||||
WSI_TOKEN_HTTP_CONTENT_ENCODING,
|
||||
WSI_TOKEN_HTTP_CONTENT_LANGUAGE,
|
||||
WSI_TOKEN_HTTP_CONTENT_LOCATION,
|
||||
WSI_TOKEN_HTTP_CONTENT_RANGE,
|
||||
WSI_TOKEN_HTTP_ETAG,
|
||||
WSI_TOKEN_HTTP_EXPECT,
|
||||
WSI_TOKEN_HTTP_EXPIRES,
|
||||
WSI_TOKEN_HTTP_FROM,
|
||||
WSI_TOKEN_HTTP_IF_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_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,
|
||||
|
||||
WSI_TOKEN_HTTP_URI_ARGS,
|
||||
|
||||
WSI_TOKEN_MUXURL,
|
||||
|
||||
/* use token storage to stash these */
|
||||
|
||||
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
|
||||
|
|
|
@ -57,6 +57,45 @@ const char *set[] = {
|
|||
"sec-websocket-key:",
|
||||
"sec-websocket-version:",
|
||||
"sec-websocket-origin:",
|
||||
|
||||
":authority:",
|
||||
":method:",
|
||||
":path:",
|
||||
":scheme:",
|
||||
":status:",
|
||||
|
||||
"accept-charset:",
|
||||
"accept-ranges:",
|
||||
"access-control-allow-origin:",
|
||||
"age:",
|
||||
"allow:",
|
||||
"content-disposition:",
|
||||
"content-language:",
|
||||
"content-location:",
|
||||
"content-range:",
|
||||
"etag:",
|
||||
"expect:",
|
||||
"expires:",
|
||||
"from:",
|
||||
"if-match:",
|
||||
"if-range:",
|
||||
"if-unmodified-since:",
|
||||
"last-modified:",
|
||||
"link:",
|
||||
"location:",
|
||||
"max-forwards:",
|
||||
"proxy-authenticate:",
|
||||
"proxy-authorization:",
|
||||
"refresh:",
|
||||
"retry-after:",
|
||||
"server:",
|
||||
"set-cookie:",
|
||||
"strict-transport-security:",
|
||||
"transfer-encoding:",
|
||||
"user-agent:",
|
||||
"vary:",
|
||||
"via:",
|
||||
"www-authenticate:",
|
||||
|
||||
"", /* not matchable */
|
||||
|
||||
|
|
|
@ -614,6 +614,15 @@ struct http2_settings {
|
|||
unsigned int setting[LWS_HTTP2_SETTINGS__COUNT];
|
||||
};
|
||||
|
||||
enum http2_hpack_state {
|
||||
HPKS_TYPE,
|
||||
|
||||
HPKS_HLEN,
|
||||
HPKS_HLEN_EXT,
|
||||
|
||||
HPKS_DATA,
|
||||
};
|
||||
|
||||
struct _lws_http2_related {
|
||||
/*
|
||||
* having this first lets us also re-use all HTTP union code
|
||||
|
@ -638,6 +647,14 @@ struct _lws_http2_related {
|
|||
unsigned char flags;
|
||||
unsigned char frame_state;
|
||||
|
||||
/* hpack */
|
||||
enum http2_hpack_state hpack;
|
||||
unsigned int header_index;
|
||||
unsigned int hpack_len;
|
||||
unsigned char hpack_m;
|
||||
unsigned int huff:1;
|
||||
unsigned int value:1;
|
||||
|
||||
unsigned int tx_credit;
|
||||
unsigned int my_stream_id;
|
||||
unsigned int child_count;
|
||||
|
|
Loading…
Add table
Reference in a new issue