mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 2.14.0
- [API] Use lsxpack_header structure to send HTTP headers. - [OPTIMIZATION] nocopy's readable_bytes() function. - http_server: fix typo in error message - Use ls-hpack 2.1.0. - Use ls-qpack 2.0.0.
This commit is contained in:
parent
a686ef2a56
commit
55613f4414
31 changed files with 10666 additions and 10735 deletions
|
@ -1 +1 @@
|
|||
Subproject commit d34c8c34dfb868417fbe14403f99290074341285
|
||||
Subproject commit 606208599650d51f03f26afd12625c62a1be7cbb
|
|
@ -196,11 +196,9 @@ lsquic_conn_get_engine (struct lsquic_conn *lconn)
|
|||
|
||||
int
|
||||
lsquic_conn_push_stream (struct lsquic_conn *lconn, void *hset,
|
||||
struct lsquic_stream *stream, const struct iovec* url,
|
||||
const struct iovec *authority, const struct lsquic_http_headers *headers)
|
||||
struct lsquic_stream *stream, const struct lsquic_http_headers *headers)
|
||||
{
|
||||
return lconn->cn_if->ci_push_stream(lconn, hset, stream, url, authority,
|
||||
headers);
|
||||
return lconn->cn_if->ci_push_stream(lconn, hset, stream, headers);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -194,7 +194,6 @@ struct conn_iface
|
|||
|
||||
int
|
||||
(*ci_push_stream) (struct lsquic_conn *, void *hset, struct lsquic_stream *,
|
||||
const struct iovec* url, const struct iovec* authority,
|
||||
const struct lsquic_http_headers *headers);
|
||||
|
||||
/* Use this to abort the connection when unlikely errors occur */
|
||||
|
|
|
@ -538,6 +538,8 @@ nocopy_di_readable_bytes (struct data_in *data_in, uint64_t read_offset)
|
|||
TAILQ_FOREACH(frame, &ncdi->ncdi_frames_in, next_frame)
|
||||
if (DF_ROFF(frame) == read_offset)
|
||||
read_offset += DF_END(frame) - DF_ROFF(frame);
|
||||
else if (read_offset > starting_offset)
|
||||
break;
|
||||
|
||||
return read_offset - starting_offset;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "lsquic_util.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_conn.h"
|
||||
#include "lsxpack_header.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_EVENT
|
||||
#include "lsquic_logger.h"
|
||||
|
@ -506,19 +507,19 @@ lsquic_ev_log_generated_http_headers (const lsquic_cid_t *cid,
|
|||
}
|
||||
|
||||
for (i = 0; i < headers->count; ++i)
|
||||
LCID(" %.*s: %.*s",
|
||||
(int) headers->headers[i].name.iov_len,
|
||||
(char *) headers->headers[i].name.iov_base,
|
||||
(int) headers->headers[i].value.iov_len,
|
||||
(char *) headers->headers[i].value.iov_base);
|
||||
if (headers->headers[i].buf)
|
||||
LCID(" %.*s: %.*s",
|
||||
(int) headers->headers[i].name_len,
|
||||
lsxpack_header_get_name(&headers->headers[i]),
|
||||
(int) headers->headers[i].val_len,
|
||||
lsxpack_header_get_value(&headers->headers[i]));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_http_push_promise (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id, lsquic_stream_id_t promised_stream_id,
|
||||
const struct lsquic_http_headers *headers,
|
||||
const struct lsquic_http_headers *extra_headers)
|
||||
const struct lsquic_http_headers *headers)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -526,19 +527,12 @@ lsquic_ev_log_generated_http_push_promise (const lsquic_cid_t *cid,
|
|||
PRIu64, stream_id, promised_stream_id);
|
||||
|
||||
for (i = 0; i < headers->count; ++i)
|
||||
LCID(" %.*s: %.*s",
|
||||
(int) headers->headers[i].name.iov_len,
|
||||
(char *) headers->headers[i].name.iov_base,
|
||||
(int) headers->headers[i].value.iov_len,
|
||||
(char *) headers->headers[i].value.iov_base);
|
||||
|
||||
if (extra_headers)
|
||||
for (i = 0; i < extra_headers->count; ++i)
|
||||
if (headers->headers[i].buf)
|
||||
LCID(" %.*s: %.*s",
|
||||
(int) extra_headers->headers[i].name.iov_len,
|
||||
(char *) extra_headers->headers[i].name.iov_base,
|
||||
(int) extra_headers->headers[i].value.iov_len,
|
||||
(char *) extra_headers->headers[i].value.iov_base);
|
||||
(int) headers->headers[i].name_len,
|
||||
lsxpack_header_get_name(&headers->headers[i]),
|
||||
(int) headers->headers[i].val_len,
|
||||
lsxpack_header_get_value(&headers->headers[i]));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -280,8 +280,7 @@ lsquic_ev_log_generated_http_headers (const lsquic_cid_t *, lsquic_stream_id_t,
|
|||
void
|
||||
lsquic_ev_log_generated_http_push_promise (const lsquic_cid_t *,
|
||||
lsquic_stream_id_t stream_id, lsquic_stream_id_t promised_stream_id,
|
||||
const struct lsquic_http_headers *headers,
|
||||
const struct lsquic_http_headers *extra_headers);
|
||||
const struct lsquic_http_headers *headers);
|
||||
|
||||
#define EV_LOG_GENERATED_HTTP_PUSH_PROMISE(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
|
|
@ -522,7 +522,7 @@ decode_and_pass_payload (struct lsquic_frame_reader *fr)
|
|||
struct lsxpack_header *hdr = NULL;
|
||||
size_t req_space = 0;
|
||||
|
||||
hset = fr->fr_hsi_if->hsi_create_header_set(fr->fr_hsi_ctx,
|
||||
hset = fr->fr_hsi_if->hsi_create_header_set(fr->fr_hsi_ctx, fr->fr_stream,
|
||||
READER_PUSH_PROMISE == fr->fr_state.reader_type);
|
||||
if (!hset)
|
||||
{
|
||||
|
|
|
@ -314,8 +314,9 @@ calc_headers_size (const struct lsquic_http_headers *headers)
|
|||
int i;
|
||||
uint32_t size = 0;
|
||||
for (i = 0; i < headers->count; ++i)
|
||||
size += 32 + headers->headers[i].name.iov_len +
|
||||
headers->headers[i].value.iov_len;
|
||||
if (headers->headers[i].buf)
|
||||
size += 32 + headers->headers[i].name_len +
|
||||
headers->headers[i].val_len;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -323,25 +324,29 @@ calc_headers_size (const struct lsquic_http_headers *headers)
|
|||
static int
|
||||
have_oversize_strings (const struct lsquic_http_headers *headers)
|
||||
{
|
||||
#if LSXPACK_MAX_STRLEN > LSHPACK_MAX_STRLEN
|
||||
int i, have;
|
||||
for (i = 0, have = 0; i < headers->count; ++i)
|
||||
{
|
||||
have |= headers->headers[i].name.iov_len > LSHPACK_MAX_STRLEN;
|
||||
have |= headers->headers[i].value.iov_len > LSHPACK_MAX_STRLEN;
|
||||
if (headers->headers[i].buf)
|
||||
{
|
||||
have |= headers->headers[i].name_len > LSHPACK_MAX_STRLEN;
|
||||
have |= headers->headers[i].val_len > LSHPACK_MAX_STRLEN;
|
||||
}
|
||||
}
|
||||
return have;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_headers_size (const struct lsquic_frame_writer *fw,
|
||||
const struct lsquic_http_headers *headers,
|
||||
const struct lsquic_http_headers *extra_headers)
|
||||
const struct lsquic_http_headers *headers)
|
||||
{
|
||||
uint32_t headers_sz;
|
||||
headers_sz = calc_headers_size(headers);
|
||||
if (extra_headers)
|
||||
headers_sz += calc_headers_size(extra_headers);
|
||||
|
||||
if (headers_sz <= fw->fw_max_header_list_sz)
|
||||
return 0;
|
||||
|
@ -369,8 +374,10 @@ check_headers_case (const struct lsquic_frame_writer *fw,
|
|||
int i;
|
||||
n_uppercase = 0;
|
||||
for (i = 0; i < headers->count; ++i)
|
||||
n_uppercase += count_uppercase(headers->headers[i].name.iov_base,
|
||||
headers->headers[i].name.iov_len);
|
||||
if (headers->headers[i].buf)
|
||||
n_uppercase += count_uppercase((unsigned char *)
|
||||
lsxpack_header_get_name(&headers->headers[i]),
|
||||
headers->headers[i].name_len);
|
||||
if (n_uppercase)
|
||||
{
|
||||
LSQ_INFO("Uppercase letters in header names");
|
||||
|
@ -389,13 +396,12 @@ write_headers (struct lsquic_frame_writer *fw,
|
|||
{
|
||||
unsigned char *end;
|
||||
int i, s;
|
||||
struct lsxpack_header hdr;
|
||||
for (i = 0; i < headers->count; ++i)
|
||||
{
|
||||
lsquic_http_header_t *h = &headers->headers[i];
|
||||
lsxpack_header_set_ptr(&hdr, h->name.iov_base, h->name.iov_len,
|
||||
h->value.iov_base, h->value.iov_len);
|
||||
end = lshpack_enc_encode(fw->fw_henc, buf, buf + buf_sz, &hdr);
|
||||
if (headers->headers[i].buf == NULL)
|
||||
continue;
|
||||
end = lshpack_enc_encode(fw->fw_henc, buf, buf + buf_sz,
|
||||
&headers->headers[i]);
|
||||
if (end > buf)
|
||||
{
|
||||
s = hfc_write(hfc, buf, end - buf);
|
||||
|
@ -403,8 +409,8 @@ write_headers (struct lsquic_frame_writer *fw,
|
|||
return s;
|
||||
#if LSQUIC_CONN_STATS
|
||||
fw->fw_conn_stats->out.headers_uncomp +=
|
||||
headers->headers[i].name.iov_len
|
||||
+ headers->headers[i].value.iov_len;
|
||||
headers->headers[i].name_len
|
||||
+ headers->headers[i].val_len;
|
||||
fw->fw_conn_stats->out.headers_comp += end - buf;
|
||||
#endif
|
||||
}
|
||||
|
@ -433,7 +439,7 @@ lsquic_frame_writer_write_headers (struct lsquic_frame_writer *fw,
|
|||
/* Internal function: weight must be valid here */
|
||||
assert(weight >= 1 && weight <= 256);
|
||||
|
||||
if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers, NULL))
|
||||
if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers))
|
||||
return -1;
|
||||
|
||||
if (0 != check_headers_case(fw, headers))
|
||||
|
@ -482,47 +488,22 @@ lsquic_frame_writer_write_headers (struct lsquic_frame_writer *fw,
|
|||
int
|
||||
lsquic_frame_writer_write_promise (struct lsquic_frame_writer *fw,
|
||||
lsquic_stream_id_t stream_id64, lsquic_stream_id_t promised_stream_id64,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *extra_headers)
|
||||
const struct lsquic_http_headers *headers)
|
||||
{
|
||||
uint32_t stream_id = stream_id64;
|
||||
uint32_t promised_stream_id = promised_stream_id64;
|
||||
struct header_framer_ctx hfc;
|
||||
struct http_push_promise_frame push_frame;
|
||||
lsquic_http_header_t mpas_headers[4];
|
||||
struct lsquic_http_headers mpas = { /* method, path, authority, scheme */
|
||||
.headers = mpas_headers,
|
||||
.count = 4,
|
||||
};
|
||||
unsigned char *buf;
|
||||
int s;
|
||||
|
||||
mpas_headers[0].name. iov_base = ":method";
|
||||
mpas_headers[0].name. iov_len = 7;
|
||||
mpas_headers[0].value.iov_base = "GET";
|
||||
mpas_headers[0].value.iov_len = 3;
|
||||
mpas_headers[1].name .iov_base = ":path";
|
||||
mpas_headers[1].name .iov_len = 5;
|
||||
mpas_headers[1].value = *path;
|
||||
mpas_headers[2].name .iov_base = ":authority";
|
||||
mpas_headers[2].name .iov_len = 10;
|
||||
mpas_headers[2].value = *host;
|
||||
mpas_headers[3].name. iov_base = ":scheme";
|
||||
mpas_headers[3].name. iov_len = 7;
|
||||
mpas_headers[3].value.iov_base = "https";
|
||||
mpas_headers[3].value.iov_len = 5;
|
||||
|
||||
if (fw->fw_max_header_list_sz &&
|
||||
0 != check_headers_size(fw, &mpas, extra_headers))
|
||||
if (fw->fw_max_header_list_sz && 0 != check_headers_size(fw, headers))
|
||||
return -1;
|
||||
|
||||
if (extra_headers && 0 != check_headers_case(fw, extra_headers))
|
||||
if (0 != check_headers_case(fw, headers))
|
||||
return -1;
|
||||
|
||||
if (have_oversize_strings(&mpas))
|
||||
return -1;
|
||||
|
||||
if (extra_headers && have_oversize_strings(extra_headers))
|
||||
if (have_oversize_strings(headers))
|
||||
return -1;
|
||||
|
||||
hfc_init(&hfc, fw, fw->fw_max_frame_sz, HTTP_FRAME_PUSH_PROMISE,
|
||||
|
@ -538,22 +519,19 @@ lsquic_frame_writer_write_promise (struct lsquic_frame_writer *fw,
|
|||
if (!buf)
|
||||
return -1;
|
||||
|
||||
s = write_headers(fw, &mpas, &hfc, buf, MAX_COMP_HEADER_FIELD_SIZE);
|
||||
s = write_headers(fw, headers, &hfc, buf, MAX_COMP_HEADER_FIELD_SIZE);
|
||||
if (s != 0)
|
||||
{
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (extra_headers)
|
||||
s = write_headers(fw, extra_headers, &hfc, buf, MAX_COMP_HEADER_FIELD_SIZE);
|
||||
|
||||
free(buf);
|
||||
|
||||
if (0 == s)
|
||||
{
|
||||
EV_LOG_GENERATED_HTTP_PUSH_PROMISE(LSQUIC_LOG_CONN_ID, stream_id,
|
||||
htonl(promised_stream_id), &mpas, extra_headers);
|
||||
htonl(promised_stream_id), headers);
|
||||
hfc_terminate_frame(&hfc, HFHF_END_HEADERS);
|
||||
return lsquic_frame_writer_flush(fw);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ lsquic_frame_writer_write_priority (struct lsquic_frame_writer *,
|
|||
int
|
||||
lsquic_frame_writer_write_promise (struct lsquic_frame_writer *,
|
||||
lsquic_stream_id_t stream_id, lsquic_stream_id_t promised_stream_id,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *headers);
|
||||
|
||||
void
|
||||
|
|
|
@ -3905,115 +3905,15 @@ headers_stream_on_priority (void *ctx, lsquic_stream_id_t stream_id,
|
|||
|
||||
static struct uncompressed_headers *
|
||||
synthesize_push_request (struct full_conn *conn, void *hset,
|
||||
const struct iovec* path, const struct iovec* host,
|
||||
const lsquic_http_headers_t *headers,
|
||||
lsquic_stream_id_t pushed_stream_id, const lsquic_stream_t *dep_stream)
|
||||
{
|
||||
struct uncompressed_headers *uh;
|
||||
struct http1x_ctor_ctx ctor_ctx;
|
||||
void *hsi_ctx;
|
||||
unsigned idx, i, n_headers;
|
||||
const lsquic_http_header_t *header;
|
||||
int st;
|
||||
lsquic_http_header_t pseudo_headers[4];
|
||||
lsquic_http_headers_t all_headers[2];
|
||||
struct lsxpack_header *xhdr;
|
||||
size_t req_space;
|
||||
|
||||
if (!hset)
|
||||
{
|
||||
if (conn->fc_enpub->enp_hsi_if == lsquic_http1x_if)
|
||||
{
|
||||
ctor_ctx = (struct http1x_ctor_ctx)
|
||||
{
|
||||
.conn = &conn->fc_conn,
|
||||
.is_server = 1,
|
||||
.max_headers_sz = MAX_HTTP1X_HEADERS_SIZE,
|
||||
};
|
||||
hsi_ctx = &ctor_ctx;
|
||||
}
|
||||
else
|
||||
hsi_ctx = conn->fc_enpub->enp_hsi_ctx;
|
||||
|
||||
hset = conn->fc_enpub->enp_hsi_if->hsi_create_header_set(hsi_ctx, 1);
|
||||
if (!hset)
|
||||
{
|
||||
LSQ_INFO("header set ctor failure");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pseudo_headers[0].name. iov_base = ":method";
|
||||
pseudo_headers[0].name. iov_len = 7;
|
||||
pseudo_headers[0].value.iov_base = "GET";
|
||||
pseudo_headers[0].value.iov_len = 3;
|
||||
pseudo_headers[1].name .iov_base = ":path";
|
||||
pseudo_headers[1].name .iov_len = 5;
|
||||
pseudo_headers[1].value = *path;
|
||||
pseudo_headers[2].name .iov_base = ":authority";
|
||||
pseudo_headers[2].name .iov_len = 10;
|
||||
pseudo_headers[2].value = *host;
|
||||
pseudo_headers[3].name. iov_base = ":scheme";
|
||||
pseudo_headers[3].name. iov_len = 7;
|
||||
pseudo_headers[3].value.iov_base = "https";
|
||||
pseudo_headers[3].value.iov_len = 5;
|
||||
|
||||
all_headers[0].headers = pseudo_headers;
|
||||
all_headers[0].count = sizeof(pseudo_headers)
|
||||
/ sizeof(pseudo_headers[0]);
|
||||
if (headers)
|
||||
{
|
||||
all_headers[1] = *headers;
|
||||
n_headers = 2;
|
||||
}
|
||||
else
|
||||
n_headers = 1;
|
||||
|
||||
for (i = 0; i < n_headers; ++i)
|
||||
for (header = all_headers[i].headers;
|
||||
header < all_headers[i].headers + all_headers[i].count;
|
||||
++header)
|
||||
{
|
||||
req_space = header->name.iov_len + header->value.iov_len + 4;
|
||||
xhdr = conn->fc_enpub->enp_hsi_if->hsi_prepare_decode(hset,
|
||||
NULL, req_space);
|
||||
if (!xhdr)
|
||||
{
|
||||
st = -__LINE__;
|
||||
goto err;
|
||||
}
|
||||
memcpy(xhdr->buf + xhdr->name_offset, header->name.iov_base,
|
||||
header->name.iov_len);
|
||||
xhdr->name_len = header->name.iov_len;
|
||||
memcpy(xhdr->buf + xhdr->name_offset + xhdr->name_len, ": ", 2);
|
||||
xhdr->val_offset = xhdr->name_offset + xhdr->name_len + 2;
|
||||
memcpy(xhdr->buf + xhdr->val_offset, header->value.iov_base,
|
||||
header->value.iov_len);
|
||||
xhdr->val_len = header->value.iov_len;
|
||||
memcpy(xhdr->buf + xhdr->name_offset + xhdr->name_len + 2
|
||||
+ xhdr->val_len, "\r\n", 2);
|
||||
xhdr->dec_overhead = 4;
|
||||
idx = lshpack_enc_get_stx_tab_id(xhdr);
|
||||
if (idx)
|
||||
{
|
||||
xhdr->flags |= LSXPACK_HPACK_IDX;
|
||||
xhdr->hpack_index = idx;
|
||||
}
|
||||
st = conn->fc_enpub->enp_hsi_if->hsi_process_header(hset, xhdr);
|
||||
if (st)
|
||||
goto err;
|
||||
}
|
||||
|
||||
st = conn->fc_enpub->enp_hsi_if->hsi_process_header(hset, NULL);
|
||||
if (st)
|
||||
goto err;
|
||||
}
|
||||
assert(hset);
|
||||
|
||||
uh = malloc(sizeof(*uh));
|
||||
if (!uh)
|
||||
{
|
||||
st = -__LINE__;
|
||||
goto err;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
uh->uh_stream_id = pushed_stream_id;
|
||||
uh->uh_oth_stream_id = 0; /* We don't do dependencies */
|
||||
|
@ -4025,10 +3925,6 @@ synthesize_push_request (struct full_conn *conn, void *hset,
|
|||
uh->uh_hset = hset;
|
||||
|
||||
return uh;
|
||||
|
||||
err:
|
||||
LSQ_INFO("%s: error %d", __func__, st);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4042,8 +3938,7 @@ full_conn_ci_is_push_enabled (struct lsquic_conn *lconn)
|
|||
|
||||
static int
|
||||
full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
||||
struct lsquic_stream *dep_stream, const struct iovec *path,
|
||||
const struct iovec *host, const struct lsquic_http_headers *headers)
|
||||
struct lsquic_stream *dep_stream, const struct lsquic_http_headers *headers)
|
||||
{
|
||||
struct full_conn *const conn = (struct full_conn *) lconn;
|
||||
lsquic_stream_t *pushed_stream;
|
||||
|
@ -4070,6 +3965,12 @@ full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!hset)
|
||||
{
|
||||
LSQ_ERROR("header set must be specified when pushing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hit_limit = 0;
|
||||
if (either_side_going_away(conn) ||
|
||||
(hit_limit = 1, count_streams(conn, 0) >= conn->fc_cfg.max_streams_out))
|
||||
|
@ -4080,8 +3981,7 @@ full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
}
|
||||
|
||||
stream_id = generate_stream_id(conn);
|
||||
uh = synthesize_push_request(conn, hset, path, host, headers, stream_id,
|
||||
dep_stream);
|
||||
uh = synthesize_push_request(conn, hset, stream_id, dep_stream);
|
||||
if (!uh)
|
||||
{
|
||||
ABORT_ERROR("memory allocation failure");
|
||||
|
@ -4104,7 +4004,7 @@ full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
}
|
||||
|
||||
if (0 != lsquic_headers_stream_push_promise(conn->fc_pub.u.gquic.hs, dep_stream->id,
|
||||
pushed_stream->id, path, host, headers))
|
||||
pushed_stream->id, headers))
|
||||
{
|
||||
/* Since the failure to write to HEADERS stream results in aborting
|
||||
* the connection, we do not bother rolling back.
|
||||
|
|
|
@ -3261,28 +3261,20 @@ undo_stream_creation (struct ietf_full_conn *conn,
|
|||
*/
|
||||
static int
|
||||
ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
||||
struct lsquic_stream *dep_stream, const struct iovec *path,
|
||||
const struct iovec *host, const struct lsquic_http_headers *headers)
|
||||
struct lsquic_stream *dep_stream, const struct lsquic_http_headers *headers)
|
||||
{
|
||||
struct ietf_full_conn *const conn = (struct ietf_full_conn *) lconn;
|
||||
unsigned char *header_block_buf, *end, *p;
|
||||
size_t hea_sz, enc_sz;
|
||||
ssize_t prefix_sz;
|
||||
lsquic_http_header_t pseudo_headers[4], *header;
|
||||
lsquic_http_headers_t all_headers[2];
|
||||
struct lsquic_hash_elem *el;
|
||||
struct push_promise *promise;
|
||||
struct lsquic_stream *pushed_stream;
|
||||
struct http1x_ctor_ctx ctor_ctx;
|
||||
void *hsi_ctx;
|
||||
struct uncompressed_headers *uh;
|
||||
enum lsqpack_enc_status enc_st;
|
||||
int header_st;
|
||||
unsigned i, n_header_sets;
|
||||
int own_hset, stx_tab_id;
|
||||
int i;
|
||||
unsigned char discard[2];
|
||||
struct lsxpack_header *xhdr;
|
||||
size_t req_space;
|
||||
|
||||
if (!ietf_full_conn_ci_is_push_enabled(lconn)
|
||||
|| !lsquic_stream_can_push(dep_stream))
|
||||
|
@ -3291,6 +3283,12 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!hset)
|
||||
{
|
||||
LSQ_ERROR("header set must be specified when pushing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 != lsqpack_enc_start_header(&conn->ifc_qeh.qeh_encoder, 0, 0))
|
||||
{
|
||||
LSQ_WARN("cannot start header for push stream");
|
||||
|
@ -3310,51 +3308,25 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
*/
|
||||
p = header_block_buf;
|
||||
end = header_block_buf + 0x1000;
|
||||
pseudo_headers[0].name. iov_base = ":method";
|
||||
pseudo_headers[0].name. iov_len = 7;
|
||||
pseudo_headers[0].value.iov_base = "GET";
|
||||
pseudo_headers[0].value.iov_len = 3;
|
||||
pseudo_headers[1].name .iov_base = ":path";
|
||||
pseudo_headers[1].name .iov_len = 5;
|
||||
pseudo_headers[1].value = *path;
|
||||
pseudo_headers[2].name .iov_base = ":authority";
|
||||
pseudo_headers[2].name .iov_len = 10;
|
||||
pseudo_headers[2].value = *host;
|
||||
pseudo_headers[3].name. iov_base = ":scheme";
|
||||
pseudo_headers[3].name. iov_len = 7;
|
||||
pseudo_headers[3].value.iov_base = "https";
|
||||
pseudo_headers[3].value.iov_len = 5;
|
||||
all_headers[0].headers = pseudo_headers;
|
||||
all_headers[0].count = sizeof(pseudo_headers)
|
||||
/ sizeof(pseudo_headers[0]);
|
||||
if (headers)
|
||||
{
|
||||
all_headers[1] = *headers;
|
||||
n_header_sets = 2;
|
||||
}
|
||||
else
|
||||
n_header_sets = 1;
|
||||
enc_sz = 0; /* Should not change */
|
||||
for (i = 0; i < n_header_sets; ++i)
|
||||
for (header = all_headers[i].headers;
|
||||
header < all_headers[i].headers + all_headers[i].count;
|
||||
++header)
|
||||
for (i = 0; i < headers->count; ++i)
|
||||
{
|
||||
xhdr = &headers->headers[i];
|
||||
if (!xhdr->buf)
|
||||
continue;
|
||||
hea_sz = end - p;
|
||||
enc_st = lsqpack_enc_encode(&conn->ifc_qeh.qeh_encoder, NULL,
|
||||
&enc_sz, p, &hea_sz, xhdr, LQEF_NO_HIST_UPD|LQEF_NO_DYN);
|
||||
if (enc_st == LQES_OK)
|
||||
p += hea_sz;
|
||||
else
|
||||
{
|
||||
hea_sz = end - p;
|
||||
enc_st = lsqpack_enc_encode(&conn->ifc_qeh.qeh_encoder, NULL,
|
||||
&enc_sz, p, &hea_sz, header->name.iov_base,
|
||||
header->name.iov_len, header->value.iov_base,
|
||||
header->value.iov_len, LQEF_NO_HIST_UPD|LQEF_NO_DYN);
|
||||
if (enc_st == LQES_OK)
|
||||
p += hea_sz;
|
||||
else
|
||||
{
|
||||
(void) lsqpack_enc_cancel_header(&conn->ifc_qeh.qeh_encoder);
|
||||
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
|
||||
LSQ_DEBUG("cannot encode header field for push %u", enc_st);
|
||||
return -1;
|
||||
}
|
||||
(void) lsqpack_enc_cancel_header(&conn->ifc_qeh.qeh_encoder);
|
||||
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
|
||||
LSQ_DEBUG("cannot encode header field for push %u", enc_st);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
prefix_sz = lsqpack_enc_end_header(&conn->ifc_qeh.qeh_encoder,
|
||||
discard, sizeof(discard), NULL);
|
||||
if (!(prefix_sz == 2 && discard[0] == 0 && discard[1] == 0))
|
||||
|
@ -3367,88 +3339,11 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
LSQ_DEBUG("generated push promise header block of %ld bytes",
|
||||
(long) (p - header_block_buf));
|
||||
|
||||
own_hset = !hset;
|
||||
if (!hset)
|
||||
{
|
||||
if (conn->ifc_enpub->enp_hsi_if == lsquic_http1x_if)
|
||||
{
|
||||
ctor_ctx = (struct http1x_ctor_ctx)
|
||||
{
|
||||
.conn = &conn->ifc_conn,
|
||||
.is_server = 1,
|
||||
.max_headers_sz = MAX_HTTP1X_HEADERS_SIZE,
|
||||
};
|
||||
hsi_ctx = &ctor_ctx;
|
||||
}
|
||||
else
|
||||
hsi_ctx = conn->ifc_enpub->enp_hsi_ctx;
|
||||
hset = conn->ifc_enpub->enp_hsi_if->hsi_create_header_set(hsi_ctx, 1);
|
||||
if (!hset)
|
||||
{
|
||||
LSQ_INFO("header set ctor failure");
|
||||
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < n_header_sets; ++i)
|
||||
for (header = all_headers[i].headers;
|
||||
header < all_headers[i].headers + all_headers[i].count;
|
||||
++header)
|
||||
{
|
||||
req_space = header->name.iov_len + header->value.iov_len + 4;
|
||||
xhdr = conn->ifc_enpub->enp_hsi_if->hsi_prepare_decode(hset,
|
||||
NULL, req_space);
|
||||
if (!xhdr)
|
||||
{
|
||||
header_st = -__LINE__;
|
||||
goto header_err;
|
||||
}
|
||||
memcpy(xhdr->buf + xhdr->name_offset, header->name.iov_base,
|
||||
header->name.iov_len);
|
||||
xhdr->name_len = header->name.iov_len;
|
||||
memcpy(xhdr->buf + xhdr->name_offset + xhdr->name_len, ": ", 2);
|
||||
xhdr->val_offset = xhdr->name_offset + xhdr->name_len + 2;
|
||||
memcpy(xhdr->buf + xhdr->val_offset, header->value.iov_base,
|
||||
header->value.iov_len);
|
||||
xhdr->val_len = header->value.iov_len;
|
||||
memcpy(xhdr->buf + xhdr->name_offset + xhdr->name_len + 2
|
||||
+ xhdr->val_len, "\r\n", 2);
|
||||
xhdr->dec_overhead = 4;
|
||||
stx_tab_id = lsqpack_get_stx_tab_id(header->name.iov_base,
|
||||
header->name.iov_len, header->value.iov_base,
|
||||
header->value.iov_len);
|
||||
if (stx_tab_id >= 0)
|
||||
{
|
||||
xhdr->qpack_index = stx_tab_id;
|
||||
xhdr->flags |= LSXPACK_QPACK_IDX;
|
||||
}
|
||||
header_st = conn->ifc_enpub->enp_hsi_if
|
||||
->hsi_process_header(hset, xhdr);
|
||||
if (header_st != 0)
|
||||
{
|
||||
header_err:
|
||||
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
|
||||
conn->ifc_enpub->enp_hsi_if->hsi_discard_header_set(hset);
|
||||
LSQ_DEBUG("header process error: %d", header_st);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
header_st = conn->ifc_enpub->enp_hsi_if->hsi_process_header(hset, NULL);
|
||||
if (header_st != 0)
|
||||
{
|
||||
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
|
||||
conn->ifc_enpub->enp_hsi_if->hsi_discard_header_set(hset);
|
||||
LSQ_DEBUG("header process error: %d", header_st);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pushed_stream = create_push_stream(conn);
|
||||
if (!pushed_stream)
|
||||
{
|
||||
LSQ_WARN("could not create push stream");
|
||||
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
|
||||
if (own_hset)
|
||||
conn->ifc_enpub->enp_hsi_if->hsi_discard_header_set(hset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -3457,8 +3352,6 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
{
|
||||
LSQ_WARN("stream push: cannot allocate promise");
|
||||
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
|
||||
if (own_hset)
|
||||
conn->ifc_enpub->enp_hsi_if->hsi_discard_header_set(hset);
|
||||
undo_stream_creation(conn, pushed_stream);
|
||||
return -1;
|
||||
}
|
||||
|
@ -3469,8 +3362,6 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
LSQ_WARN("stream push: cannot allocate uh");
|
||||
free(promise);
|
||||
lsquic_mm_put_4k(conn->ifc_pub.mm, header_block_buf);
|
||||
if (own_hset)
|
||||
conn->ifc_enpub->enp_hsi_if->hsi_discard_header_set(hset);
|
||||
undo_stream_creation(conn, pushed_stream);
|
||||
return -1;
|
||||
}
|
||||
|
@ -3479,8 +3370,6 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
uh->uh_weight = lsquic_stream_priority(dep_stream) / 2 + 1;
|
||||
uh->uh_exclusive = 0;
|
||||
uh->uh_flags = UH_FIN;
|
||||
if (lsquic_http1x_if == conn->ifc_enpub->enp_hsi_if)
|
||||
uh->uh_flags |= UH_H1H;
|
||||
uh->uh_hset = hset;
|
||||
|
||||
memset(promise, 0, sizeof(*promise));
|
||||
|
@ -3497,8 +3386,6 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
{
|
||||
LSQ_WARN("cannot insert push promise (ID)");
|
||||
undo_stream_creation(conn, pushed_stream);
|
||||
if (own_hset)
|
||||
conn->ifc_enpub->enp_hsi_if->hsi_discard_header_set(hset);
|
||||
lsquic_pp_put(promise, conn->ifc_pub.u.ietf.promises);
|
||||
free(uh);
|
||||
return -1;
|
||||
|
@ -3508,8 +3395,6 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
{
|
||||
LSQ_DEBUG("push promise failed");
|
||||
undo_stream_creation(conn, pushed_stream);
|
||||
if (own_hset)
|
||||
conn->ifc_enpub->enp_hsi_if->hsi_discard_header_set(hset);
|
||||
lsquic_pp_put(promise, conn->ifc_pub.u.ietf.promises);
|
||||
free(uh);
|
||||
return -1;
|
||||
|
@ -3519,8 +3404,6 @@ ietf_full_conn_ci_push_stream (struct lsquic_conn *lconn, void *hset,
|
|||
{
|
||||
LSQ_WARN("stream barfed when fed synthetic request");
|
||||
undo_stream_creation(conn, pushed_stream);
|
||||
if (own_hset)
|
||||
conn->ifc_enpub->enp_hsi_if->hsi_discard_header_set(hset);
|
||||
free(uh);
|
||||
if (0 != lsquic_hcso_write_cancel_push(&conn->ifc_hcso,
|
||||
promise->pp_id))
|
||||
|
|
|
@ -81,7 +81,17 @@ static lsquic_stream_ctx_t *
|
|||
headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
|
||||
{
|
||||
struct headers_stream *hs = stream_if_ctx;
|
||||
lshpack_dec_init(&hs->hs_hdec, LSHPACK_DEC_HTTP1X);
|
||||
enum lshpack_dec_flags flags;
|
||||
|
||||
flags = 0;
|
||||
if (hs->hs_enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HTTP1X)
|
||||
flags |= LSHPACK_DEC_HTTP1X;
|
||||
if (hs->hs_enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAME)
|
||||
flags |= LSHPACK_DEC_HASH_NAME;
|
||||
if (hs->hs_enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAMEVAL)
|
||||
flags |= LSHPACK_DEC_HASH_NAMEVAL;
|
||||
|
||||
lshpack_dec_init(&hs->hs_hdec, flags);
|
||||
if (0 != lshpack_enc_init(&hs->hs_henc))
|
||||
{
|
||||
LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno));
|
||||
|
@ -375,7 +385,6 @@ headers_on_settings (void *ctx, uint16_t setting_id, uint32_t setting_value)
|
|||
int
|
||||
lsquic_headers_stream_push_promise (struct headers_stream *hs,
|
||||
lsquic_stream_id_t stream_id64, lsquic_stream_id_t promised_stream_id64,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *headers)
|
||||
{
|
||||
uint32_t stream_id = stream_id64;
|
||||
|
@ -384,7 +393,7 @@ lsquic_headers_stream_push_promise (struct headers_stream *hs,
|
|||
LSQ_DEBUG("promising stream %u in response to stream %u",
|
||||
promised_stream_id, stream_id);
|
||||
s = lsquic_frame_writer_write_promise(hs->hs_fw, stream_id,
|
||||
promised_stream_id, path, host, headers);
|
||||
promised_stream_id, headers);
|
||||
if (0 == s)
|
||||
{
|
||||
lsquic_stream_wantwrite(hs->hs_stream,
|
||||
|
|
|
@ -60,7 +60,6 @@ lsquic_headers_stream_send_headers (struct headers_stream *hs,
|
|||
int
|
||||
lsquic_headers_stream_push_promise (struct headers_stream *hs,
|
||||
lsquic_stream_id_t stream_id, lsquic_stream_id_t promised_stream_id,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *);
|
||||
|
||||
int
|
||||
|
|
|
@ -52,7 +52,6 @@ struct header_writer_ctx
|
|||
enum pseudo_header pseh_mask;
|
||||
char *pseh_bufs[N_PSEH];
|
||||
struct http1x_headers hwc_h1h;
|
||||
char *hwc_header_buf;
|
||||
size_t hwc_header_buf_nalloc;
|
||||
struct lsxpack_header hwc_xhdr;
|
||||
};
|
||||
|
@ -63,7 +62,7 @@ struct header_writer_ctx
|
|||
#define HWC_PSEH_VAL(hwc, ph) ((hwc)->pseh_bufs[ph])
|
||||
|
||||
static void *
|
||||
h1h_create_header_set (void *ctx, int is_push_promise)
|
||||
h1h_create_header_set (void *ctx, lsquic_stream_t *stream, int is_push_promise)
|
||||
{
|
||||
const struct http1x_ctor_ctx *hcc = ctx;
|
||||
struct header_writer_ctx *hwc;
|
||||
|
@ -510,8 +509,10 @@ static struct lsxpack_header *
|
|||
h1h_prepare_decode (void *hset, struct lsxpack_header *xhdr, size_t req_space)
|
||||
{
|
||||
struct header_writer_ctx *const hwc = HWC_PTR(hset);
|
||||
size_t nalloc;
|
||||
char *buf;
|
||||
|
||||
if (0 == req_space)
|
||||
if (req_space < 0x100)
|
||||
req_space = 0x100;
|
||||
|
||||
if (req_space > MAX_HTTP1X_HEADERS_SIZE || req_space > LSXPACK_MAX_STRLEN)
|
||||
|
@ -521,21 +522,47 @@ h1h_prepare_decode (void *hset, struct lsxpack_header *xhdr, size_t req_space)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (req_space > hwc->hwc_header_buf_nalloc)
|
||||
if (!xhdr)
|
||||
{
|
||||
free(hwc->hwc_header_buf);
|
||||
hwc->hwc_header_buf_nalloc = 0;
|
||||
hwc->hwc_header_buf = malloc(req_space);
|
||||
if (!hwc->hwc_header_buf)
|
||||
if (0 == hwc->hwc_header_buf_nalloc
|
||||
|| req_space > hwc->hwc_header_buf_nalloc)
|
||||
{
|
||||
LSQ_DEBUG("cannot allocate %zd bytes", req_space);
|
||||
return NULL;
|
||||
if (req_space < 0x100)
|
||||
nalloc = 0x100;
|
||||
else
|
||||
nalloc = req_space;
|
||||
buf = malloc(nalloc);
|
||||
if (!buf)
|
||||
{
|
||||
LSQ_DEBUG("cannot allocate %zd bytes", nalloc);
|
||||
return NULL;
|
||||
}
|
||||
hwc->hwc_header_buf_nalloc = nalloc;
|
||||
}
|
||||
hwc->hwc_header_buf_nalloc = req_space;
|
||||
else
|
||||
buf = hwc->hwc_xhdr.buf;
|
||||
lsxpack_header_prepare_decode(&hwc->hwc_xhdr, buf, 0, req_space);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (req_space > hwc->hwc_header_buf_nalloc)
|
||||
{
|
||||
if (req_space < hwc->hwc_header_buf_nalloc * 2)
|
||||
nalloc = hwc->hwc_header_buf_nalloc * 2;
|
||||
else
|
||||
nalloc = req_space;
|
||||
buf = realloc(hwc->hwc_xhdr.buf, nalloc);
|
||||
if (!buf)
|
||||
{
|
||||
LSQ_DEBUG("cannot reallocate to %zd bytes", nalloc);
|
||||
return NULL;
|
||||
}
|
||||
hwc->hwc_xhdr.buf = buf;
|
||||
hwc->hwc_header_buf_nalloc = nalloc;
|
||||
}
|
||||
hwc->hwc_xhdr.val_len = req_space;
|
||||
}
|
||||
|
||||
lsxpack_header_prepare_decode(&hwc->hwc_xhdr, hwc->hwc_header_buf,
|
||||
0, hwc->hwc_header_buf_nalloc);
|
||||
return &hwc->hwc_xhdr;
|
||||
}
|
||||
|
||||
|
@ -563,7 +590,7 @@ h1h_discard_header_set (void *hset)
|
|||
if (hwc->cookie_val)
|
||||
free(hwc->cookie_val);
|
||||
free(hwc->hwc_h1h.h1h_buf);
|
||||
free(hwc->hwc_header_buf);
|
||||
free(hwc->hwc_xhdr.buf);
|
||||
free(hwc);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,25 @@
|
|||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(qdh->qdh_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
static void
|
||||
qdh_hblock_unblocked (void *);
|
||||
static const struct lsqpack_dec_hset_if dhi_if;
|
||||
|
||||
|
||||
struct header_ctx
|
||||
{
|
||||
void *hset;
|
||||
struct qpack_dec_hdl *qdh;
|
||||
};
|
||||
|
||||
|
||||
/* We need to allocate struct uncompressed_headers anyway when header set
|
||||
* is complete and we give it to the stream using lsquic_stream_uh_in().
|
||||
* To save a malloc, we reuse context after we're done with it.
|
||||
*/
|
||||
union hblock_ctx
|
||||
{
|
||||
struct header_ctx ctx;
|
||||
struct uncompressed_headers uh;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
|
@ -129,10 +146,20 @@ lsquic_qdh_init (struct qpack_dec_hdl *qdh, struct lsquic_conn *conn,
|
|||
int is_server, const struct lsquic_engine_public *enpub,
|
||||
unsigned dyn_table_size, unsigned max_risked_streams)
|
||||
{
|
||||
enum lsqpack_dec_opts dec_opts;
|
||||
|
||||
dec_opts = 0;
|
||||
if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HTTP1X)
|
||||
dec_opts |= LSQPACK_DEC_OPT_HTTP1X;
|
||||
if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAME)
|
||||
dec_opts |= LSQPACK_DEC_OPT_HASH_NAME;
|
||||
if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAMEVAL)
|
||||
dec_opts |= LSQPACK_DEC_OPT_HASH_NAMEVAL;
|
||||
|
||||
qdh->qdh_conn = conn;
|
||||
lsquic_frab_list_init(&qdh->qdh_fral, 0x400, NULL, NULL, NULL);
|
||||
lsqpack_dec_init(&qdh->qdh_decoder, (void *) conn, dyn_table_size,
|
||||
max_risked_streams, qdh_hblock_unblocked);
|
||||
max_risked_streams, &dhi_if, dec_opts);
|
||||
qdh->qdh_flags |= QDH_INITIALIZED;
|
||||
qdh->qdh_enpub = enpub;
|
||||
if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if)
|
||||
|
@ -378,7 +405,8 @@ static void
|
|||
qdh_hblock_unblocked (void *stream_p)
|
||||
{
|
||||
struct lsquic_stream *const stream = stream_p;
|
||||
struct qpack_dec_hdl *const qdh = lsquic_stream_get_qdh(stream);
|
||||
union hblock_ctx *const u = stream->sm_hblock_ctx;
|
||||
struct qpack_dec_hdl *qdh = u->ctx.qdh;
|
||||
|
||||
LSQ_DEBUG("header block for stream %"PRIu64" unblocked", stream->id);
|
||||
lsquic_stream_qdec_unblocked(stream);
|
||||
|
@ -433,159 +461,112 @@ process_content_length (const struct qpack_dec_hdl *qdh /* for logging */,
|
|||
|
||||
|
||||
static int
|
||||
is_content_length (const struct lsqpack_header *header)
|
||||
is_content_length (const struct lsxpack_header *xhdr)
|
||||
{
|
||||
return ((header->qh_flags & QH_ID_SET) && header->qh_static_id == 4)
|
||||
|| (header->qh_name_len == 14 && header->qh_name[0] == 'c'
|
||||
&& 0 == memcmp(header->qh_name + 1, "ontent-length", 13))
|
||||
return ((xhdr->flags & LSXPACK_QPACK_IDX)
|
||||
&& xhdr->qpack_index == LSQPACK_TNV_CONTENT_LENGTH_0)
|
||||
|| (xhdr->name_len == 14 && 0 == memcmp(lsxpack_header_get_name(xhdr),
|
||||
"content-length", 13))
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qdh_supply_hset_to_stream (struct qpack_dec_hdl *qdh,
|
||||
struct lsquic_stream *stream, struct lsqpack_header_list *qlist)
|
||||
static struct lsxpack_header *
|
||||
qdh_prepare_decode (void *stream_p, struct lsxpack_header *xhdr, size_t space)
|
||||
{
|
||||
const struct lsquic_hset_if *const hset_if = qdh->qdh_enpub->enp_hsi_if;
|
||||
struct uncompressed_headers *uh = NULL;
|
||||
const struct lsqpack_header *header;
|
||||
int st;
|
||||
int push_promise;
|
||||
unsigned i;
|
||||
void *hset;
|
||||
struct lsquic_stream *const stream = stream_p;
|
||||
union hblock_ctx *const u = stream->sm_hblock_ctx;
|
||||
struct qpack_dec_hdl *const qdh = u->ctx.qdh;
|
||||
|
||||
return qdh->qdh_enpub->enp_hsi_if->hsi_prepare_decode(
|
||||
u->ctx.hset, xhdr, space);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qdh_process_header (void *stream_p, struct lsxpack_header *xhdr)
|
||||
{
|
||||
struct lsquic_stream *const stream = stream_p;
|
||||
union hblock_ctx *const u = stream->sm_hblock_ctx;
|
||||
struct qpack_dec_hdl *const qdh = u->ctx.qdh;
|
||||
struct cont_len cl;
|
||||
struct lsxpack_header *xhdr;
|
||||
size_t req_space;
|
||||
|
||||
push_promise = lsquic_stream_header_is_pp(stream);
|
||||
hset = hset_if->hsi_create_header_set(qdh->qdh_hsi_ctx, push_promise);
|
||||
if (!hset)
|
||||
if (is_content_length(xhdr))
|
||||
{
|
||||
LSQ_INFO("call to hsi_create_header_set failed");
|
||||
return -1;
|
||||
cl.has = 0;
|
||||
process_content_length(qdh, &cl, lsxpack_header_get_value(xhdr),
|
||||
xhdr->val_len);
|
||||
if (cl.has > 0)
|
||||
(void) lsquic_stream_verify_len(stream, cl.value);
|
||||
}
|
||||
|
||||
LSQ_DEBUG("got header set for stream %"PRIu64, stream->id);
|
||||
|
||||
cl.has = 0;
|
||||
for (i = 0; i < qlist->qhl_count; ++i)
|
||||
{
|
||||
header = qlist->qhl_headers[i];
|
||||
LSQ_DEBUG("%.*s: %.*s", header->qh_name_len, header->qh_name,
|
||||
header->qh_value_len, header->qh_value);
|
||||
req_space = header->qh_name_len + header->qh_value_len + 4;
|
||||
xhdr = hset_if->hsi_prepare_decode(hset, NULL, req_space);
|
||||
if (!xhdr)
|
||||
{
|
||||
LSQ_DEBUG("prepare_decode(%zd) failed", req_space);
|
||||
goto err;
|
||||
}
|
||||
memcpy(xhdr->buf + xhdr->name_offset, header->qh_name,
|
||||
header->qh_name_len);
|
||||
xhdr->name_len = header->qh_name_len;
|
||||
memcpy(xhdr->buf + xhdr->name_offset + xhdr->name_len, ": ", 2);
|
||||
xhdr->val_offset = xhdr->name_offset + xhdr->name_len + 2;
|
||||
memcpy(xhdr->buf + xhdr->val_offset,
|
||||
header->qh_value, header->qh_value_len);
|
||||
xhdr->val_len = header->qh_value_len;
|
||||
memcpy(xhdr->buf + xhdr->name_offset + xhdr->name_len + 2
|
||||
+ xhdr->val_len, "\r\n", 2);
|
||||
xhdr->dec_overhead = 4;
|
||||
if (header->qh_flags & QH_ID_SET)
|
||||
{
|
||||
xhdr->flags |= LSXPACK_QPACK_IDX;
|
||||
xhdr->qpack_index = header->qh_static_id;
|
||||
}
|
||||
st = hset_if->hsi_process_header(hset, xhdr);
|
||||
if (st != 0)
|
||||
{
|
||||
LSQ_INFO("header process returned non-OK code %d", st);
|
||||
goto err;
|
||||
}
|
||||
if (is_content_length(header))
|
||||
process_content_length(qdh, &cl, header->qh_value,
|
||||
header->qh_value_len);
|
||||
}
|
||||
|
||||
lsqpack_dec_destroy_header_list(qlist);
|
||||
qlist = NULL;
|
||||
st = hset_if->hsi_process_header(hset, NULL);
|
||||
if (st != 0)
|
||||
goto err;
|
||||
|
||||
uh = calloc(1, sizeof(*uh));
|
||||
if (!uh)
|
||||
goto err;
|
||||
uh->uh_stream_id = stream->id;
|
||||
uh->uh_oth_stream_id = 0;
|
||||
uh->uh_weight = 0;
|
||||
uh->uh_exclusive = -1;
|
||||
if (hset_if == lsquic_http1x_if)
|
||||
uh->uh_flags |= UH_H1H;
|
||||
uh->uh_hset = hset;
|
||||
if (0 != lsquic_stream_uh_in(stream, uh))
|
||||
goto err;
|
||||
LSQ_DEBUG("converted qlist to hset and gave it to stream %"PRIu64,
|
||||
stream->id);
|
||||
if (cl.has > 0)
|
||||
(void) lsquic_stream_verify_len(stream, cl.value);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (qlist)
|
||||
lsqpack_dec_destroy_header_list(qlist);
|
||||
hset_if->hsi_discard_header_set(hset);
|
||||
free(uh);
|
||||
return -1;
|
||||
return qdh->qdh_enpub->enp_hsi_if->hsi_process_header(u->ctx.hset, xhdr);
|
||||
}
|
||||
|
||||
|
||||
/* Releases qlist */
|
||||
static int
|
||||
qdh_process_qlist (struct qpack_dec_hdl *qdh,
|
||||
struct lsquic_stream *stream, struct lsqpack_header_list *qlist)
|
||||
static const struct lsqpack_dec_hset_if dhi_if =
|
||||
{
|
||||
if (!lsquic_stream_header_is_trailer(stream))
|
||||
return qdh_supply_hset_to_stream(qdh, stream, qlist);
|
||||
else
|
||||
{
|
||||
LSQ_DEBUG("discard trailer header set");
|
||||
lsqpack_dec_destroy_header_list(qlist);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
.dhi_unblocked = qdh_hblock_unblocked,
|
||||
.dhi_prepare_decode = qdh_prepare_decode,
|
||||
.dhi_process_header = qdh_process_header,
|
||||
};
|
||||
|
||||
|
||||
static enum lsqpack_read_header_status
|
||||
qdh_header_read_results (struct qpack_dec_hdl *qdh,
|
||||
struct lsquic_stream *stream, enum lsqpack_read_header_status rhs,
|
||||
struct lsqpack_header_list *qlist, const unsigned char *dec_buf,
|
||||
size_t dec_buf_sz)
|
||||
const unsigned char *dec_buf, size_t dec_buf_sz)
|
||||
{
|
||||
const struct lsqpack_dec_err *qerr;
|
||||
struct uncompressed_headers *uh;
|
||||
void *hset;
|
||||
|
||||
if (rhs == LQRHS_DONE)
|
||||
{
|
||||
if (qlist)
|
||||
if (!lsquic_stream_header_is_trailer(stream))
|
||||
{
|
||||
if (0 != qdh_process_qlist(qdh, stream, qlist))
|
||||
return LQRHS_ERROR;
|
||||
if (qdh->qdh_dec_sm_out)
|
||||
hset = stream->sm_hblock_ctx->ctx.hset;
|
||||
uh = &stream->sm_hblock_ctx->uh;
|
||||
stream->sm_hblock_ctx = NULL;
|
||||
memset(uh, 0, sizeof(*uh));
|
||||
uh->uh_stream_id = stream->id;
|
||||
uh->uh_oth_stream_id = 0;
|
||||
uh->uh_weight = 0;
|
||||
uh->uh_exclusive = -1;
|
||||
if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if)
|
||||
uh->uh_flags |= UH_H1H;
|
||||
if (0 != qdh->qdh_enpub->enp_hsi_if
|
||||
->hsi_process_header(hset, NULL))
|
||||
{
|
||||
if (dec_buf_sz
|
||||
&& 0 != qdh_write_decoder(qdh, dec_buf, dec_buf_sz))
|
||||
{
|
||||
return LQRHS_ERROR;
|
||||
}
|
||||
if (dec_buf_sz || lsqpack_dec_ici_pending(&qdh->qdh_decoder))
|
||||
lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1);
|
||||
LSQ_DEBUG("finishing HTTP/1.x hset failed");
|
||||
free(uh);
|
||||
return LQRHS_ERROR;
|
||||
}
|
||||
uh->uh_hset = hset;
|
||||
if (0 == lsquic_stream_uh_in(stream, uh))
|
||||
LSQ_DEBUG("gave hset to stream %"PRIu64, stream->id);
|
||||
else
|
||||
{
|
||||
LSQ_DEBUG("could not give hset to stream %"PRIu64, stream->id);
|
||||
free(uh);
|
||||
return LQRHS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("read header status is DONE but header list is not set");
|
||||
assert(0);
|
||||
return LQRHS_ERROR;
|
||||
LSQ_DEBUG("discard trailer header set");
|
||||
free(stream->sm_hblock_ctx);
|
||||
stream->sm_hblock_ctx = NULL;
|
||||
}
|
||||
if (qdh->qdh_dec_sm_out)
|
||||
{
|
||||
if (dec_buf_sz
|
||||
&& 0 != qdh_write_decoder(qdh, dec_buf, dec_buf_sz))
|
||||
{
|
||||
return LQRHS_ERROR;
|
||||
}
|
||||
if (dec_buf_sz || lsqpack_dec_ici_pending(&qdh->qdh_decoder))
|
||||
lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1);
|
||||
}
|
||||
}
|
||||
else if (rhs == LQRHS_ERROR)
|
||||
|
@ -607,24 +588,43 @@ lsquic_qdh_header_in_begin (struct qpack_dec_hdl *qdh,
|
|||
const unsigned char **buf, size_t bufsz)
|
||||
{
|
||||
enum lsqpack_read_header_status rhs;
|
||||
struct lsqpack_header_list *qlist;
|
||||
void *hset;
|
||||
int is_pp;
|
||||
size_t dec_buf_sz;
|
||||
union hblock_ctx *u;
|
||||
unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK];
|
||||
|
||||
if (qdh->qdh_flags & QDH_INITIALIZED)
|
||||
{
|
||||
dec_buf_sz = sizeof(dec_buf);
|
||||
rhs = lsqpack_dec_header_in(&qdh->qdh_decoder, stream, stream->id,
|
||||
header_size, buf, bufsz, &qlist, dec_buf, &dec_buf_sz);
|
||||
return qdh_header_read_results(qdh, stream, rhs, qlist, dec_buf,
|
||||
dec_buf_sz);
|
||||
}
|
||||
else
|
||||
if (!(qdh->qdh_flags & QDH_INITIALIZED))
|
||||
{
|
||||
LSQ_WARN("not initialized: cannot process header block");
|
||||
return LQRHS_ERROR;
|
||||
}
|
||||
|
||||
u = malloc(sizeof(*u));
|
||||
if (!u)
|
||||
{
|
||||
LSQ_INFO("cannot allocate hblock_ctx");
|
||||
return LQRHS_ERROR;
|
||||
}
|
||||
|
||||
is_pp = lsquic_stream_header_is_pp(stream);
|
||||
hset = qdh->qdh_enpub->enp_hsi_if->hsi_create_header_set(
|
||||
qdh->qdh_hsi_ctx, stream, is_pp);
|
||||
if (!hset)
|
||||
{
|
||||
free(u);
|
||||
LSQ_DEBUG("hsi_create_header_set failure");
|
||||
return LQRHS_ERROR;
|
||||
}
|
||||
|
||||
u->ctx.hset = hset;
|
||||
u->ctx.qdh = qdh;
|
||||
stream->sm_hblock_ctx = u;
|
||||
|
||||
dec_buf_sz = sizeof(dec_buf);
|
||||
rhs = lsqpack_dec_header_in(&qdh->qdh_decoder, stream, stream->id,
|
||||
header_size, buf, bufsz, dec_buf, &dec_buf_sz);
|
||||
return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz);
|
||||
}
|
||||
|
||||
|
||||
|
@ -633,7 +633,6 @@ lsquic_qdh_header_in_continue (struct qpack_dec_hdl *qdh,
|
|||
struct lsquic_stream *stream, const unsigned char **buf, size_t bufsz)
|
||||
{
|
||||
enum lsqpack_read_header_status rhs;
|
||||
struct lsqpack_header_list *qlist;
|
||||
size_t dec_buf_sz;
|
||||
unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK];
|
||||
|
||||
|
@ -641,9 +640,8 @@ lsquic_qdh_header_in_continue (struct qpack_dec_hdl *qdh,
|
|||
{
|
||||
dec_buf_sz = sizeof(dec_buf);
|
||||
rhs = lsqpack_dec_header_read(&qdh->qdh_decoder, stream,
|
||||
buf, bufsz, &qlist, dec_buf, &dec_buf_sz);
|
||||
return qdh_header_read_results(qdh, stream, rhs, qlist, dec_buf,
|
||||
dec_buf_sz);
|
||||
buf, bufsz, dec_buf, &dec_buf_sz);
|
||||
return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "lsquic_stream.h"
|
||||
#include "lsquic_frab_list.h"
|
||||
#include "lsqpack.h"
|
||||
#include "lsxpack_header.h"
|
||||
#include "lsquic_conn.h"
|
||||
#include "lsquic_qenc_hdl.h"
|
||||
|
||||
|
@ -354,22 +355,21 @@ qeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
|
|||
total_enc_sz = 0;
|
||||
for (i = 0; i < headers->count; ++i)
|
||||
{
|
||||
if (headers->headers[i].buf == NULL)
|
||||
continue;
|
||||
enc_sz = sizeof(enc_buf);
|
||||
hea_sz = end - p;
|
||||
st = lsqpack_enc_encode(&qeh->qeh_encoder, enc_buf, &enc_sz, p,
|
||||
&hea_sz, headers->headers[i].name.iov_base,
|
||||
headers->headers[i].name.iov_len,
|
||||
headers->headers[i].value.iov_base,
|
||||
headers->headers[i].value.iov_len, enc_flags);
|
||||
&hea_sz, &headers->headers[i], enc_flags);
|
||||
switch (st)
|
||||
{
|
||||
case LQES_OK:
|
||||
LSQ_DEBUG("encoded `%.*s': `%.*s' -- %zd bytes to header block, "
|
||||
"%zd bytes to encoder stream",
|
||||
(int) headers->headers[i].name.iov_len,
|
||||
(char *) headers->headers[i].name.iov_base,
|
||||
(int) headers->headers[i].value.iov_len,
|
||||
(char *) headers->headers[i].value.iov_base,
|
||||
(int) headers->headers[i].name_len,
|
||||
lsxpack_header_get_name(&headers->headers[i]),
|
||||
(int) headers->headers[i].val_len,
|
||||
lsxpack_header_get_value(&headers->headers[i]),
|
||||
hea_sz, enc_sz);
|
||||
total_enc_sz += enc_sz;
|
||||
p += hea_sz;
|
||||
|
|
|
@ -4013,12 +4013,6 @@ lsquic_stream_get_hset (struct lsquic_stream *stream)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (stream->uh->uh_flags & UH_H1H)
|
||||
{
|
||||
LSQ_INFO("%s: uncompressed headers have internal format", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hset = stream->uh->uh_hset;
|
||||
stream->uh->uh_hset = NULL;
|
||||
destroy_uh(stream);
|
||||
|
@ -4432,13 +4426,6 @@ hq_decr_left (struct lsquic_stream *stream, size_t read)
|
|||
}
|
||||
|
||||
|
||||
struct qpack_dec_hdl *
|
||||
lsquic_stream_get_qdh (const struct lsquic_stream *stream)
|
||||
{
|
||||
return stream->conn_pub->u.ietf.qdh;
|
||||
}
|
||||
|
||||
|
||||
/* These are IETF QUIC states */
|
||||
enum stream_state_sending
|
||||
lsquic_stream_sending_state (const struct lsquic_stream *stream)
|
||||
|
|
|
@ -16,6 +16,7 @@ struct frame_gen_ctx;
|
|||
struct data_frame;
|
||||
enum quic_frame_type;
|
||||
struct push_promise;
|
||||
union hblock_ctx;
|
||||
|
||||
TAILQ_HEAD(lsquic_streams_tailq, lsquic_stream);
|
||||
|
||||
|
@ -165,7 +166,7 @@ enum stream_q_flags
|
|||
SMQF_FREE_STREAM = 1 << 7,
|
||||
SMQF_ABORT_CONN = 1 << 8, /* Unrecoverable error occurred */
|
||||
|
||||
SMQF_QPACK_DEC = 1 << 9, /* QPACK decoder is holding a reference to this stream */
|
||||
SMQF_QPACK_DEC = 1 << 9, /* QPACK decoder handler is holding a reference to this stream */
|
||||
};
|
||||
|
||||
|
||||
|
@ -283,6 +284,7 @@ struct lsquic_stream
|
|||
|
||||
struct uncompressed_headers *uh,
|
||||
*push_req;
|
||||
union hblock_ctx *sm_hblock_ctx;
|
||||
|
||||
unsigned char *sm_buf;
|
||||
void *sm_onnew_arg;
|
||||
|
@ -538,9 +540,6 @@ void
|
|||
lsquic_stream_set_stream_if (struct lsquic_stream *,
|
||||
const struct lsquic_stream_if *, void *stream_if_ctx);
|
||||
|
||||
struct qpack_dec_hdl *
|
||||
lsquic_stream_get_qdh (const struct lsquic_stream *);
|
||||
|
||||
uint64_t
|
||||
lsquic_stream_combined_send_off (const struct lsquic_stream *);
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f483bed42c955d98400305296c91587c9d4b26ad
|
||||
Subproject commit f209bb5e9af8dbb14c22b214519c8ea5ebaecb5d
|
Loading…
Add table
Add a link
Reference in a new issue