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:
Dmitri Tikhonov 2020-03-30 13:34:43 -04:00
parent a686ef2a56
commit 55613f4414
31 changed files with 10666 additions and 10735 deletions

View File

@ -1,3 +1,11 @@
2020-03-30
- 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.
2020-03-23
- 2.13.3
- [BUGFIX] ACK ping-pong: TIMESTAMP frame is not to be acked.

View File

@ -1350,17 +1350,70 @@ for both reading and writing,
Sending HTTP Headers
--------------------
.. type:: lsquic_http_header_t
.. type:: struct lsxpack_header
.. member:: struct iovec name
This type is defined in _lsxpack_header.h_. See that header file for
more information.
Header name.
.. member:: char *buf
.. member:: struct iovec value
the buffer for headers
Header value.
.. member:: const char *name_ptr
HTTP header structure. Contains header name and value.
the name pointer can be optionally set for encoding
.. member:: uint32_t name_hash
hash value for name
.. member:: uint32_t nameval_hash
hash value for name + value
.. member:: lsxpack_strlen_t name_offset
the offset for name in the buffer
.. member:: lsxpack_strlen_t name_len
the length of name
.. member:: lsxpack_strlen_t val_offset
the offset for value in the buffer
.. member:: lsxpack_strlen_t val_len
the length of value
.. member:: uint16_t chain_next_idx
mainly for cookie value chain
.. member:: uint8_t hpack_index
HPACK static table index
.. member:: uint8_t qpack_index
QPACK static table index
.. member:: uint8_t app_index
APP header index
.. member:: enum lsxpack_flag flags:8
combination of lsxpack_flag
.. member:: uint8_t indexed_type
control to disable index or not
.. member:: uint8_t dec_overhead
num of extra bytes written to decoded buffer
.. type:: lsquic_http_headers_t
@ -1368,11 +1421,11 @@ Sending HTTP Headers
Number of headers in ``headers``.
.. member:: lsquic_http_header_t *headers
.. member:: struct lsxpack_header *headers
Pointer to an array of HTTP headers.
HTTP header list structure. Contains a list of HTTP headers in key/value pairs.
HTTP header list structure. Contains a list of HTTP headers.
.. function:: int lsquic_stream_send_headers (lsquic_stream_t *stream, const lsquic_http_headers_t *headers, int eos)
@ -1407,9 +1460,10 @@ fields yourself. In that case, the header set must be "read" from the stream vi
.. type:: struct lsquic_hset_if
.. member:: void * (*hsi_create_header_set)(void *hsi_ctx, int is_push_promise)
.. member:: void * (*hsi_create_header_set)(void *hsi_ctx, lsquic_stream_t *stream, int is_push_promise)
:param hsi_ctx: User context. This is the pointer specifed in ``ea_hsi_ctx``.
:param stream: Stream with which the header set is associated.
:param is_push_promise: Boolean value indicating whether this header set is
for a push promise.
:return: Pointer to user-defined header set object.
@ -1459,6 +1513,11 @@ fields yourself. In that case, the header set must be "read" from the stream vi
Discard header set. This is called for unclaimed header sets and
header sets that had an error.
.. member:: enum lsquic_hsi_flag hsi_flags
These flags specify properties of decoded headers passed to
``hsi_process_header()``.
.. function:: void * lsquic_stream_get_hset (lsquic_stream_t *stream)
:param stream: Stream to fetch header set from.
@ -1478,7 +1537,7 @@ fields yourself. In that case, the header set must be "read" from the stream vi
Push Promises
-------------
.. function:: int lsquic_conn_push_stream (lsquic_conn_t *conn, void *hdr_set, lsquic_stream_t *stream, const struct iovec* url, const struct iovec* authority, const lsquic_http_headers_t *headers)
.. function:: int lsquic_conn_push_stream (lsquic_conn_t *conn, void *hdr_set, lsquic_stream_t *stream, const lsquic_http_headers_t *headers)
:return:
@ -1491,10 +1550,7 @@ Push Promises
to stream ``stream``. It will behave as if the client made a request: it will
trigger ``on_new_stream()`` event and it can be used as a regular client-initiated stream.
If ``hdr_set`` is not set, it is generated by using ``ea_hsi_if`` callbacks (if set).
In either case, the header set object belongs to the connection. The
user is not to free this object until ``hsi_discard_header_set()`` is
called.
``hdr_set`` must be set. It is passed as-is to :func:`lsquic_stream_get_hset()`.
.. function:: int lsquic_conn_is_push_enabled (lsquic_conn_t *conn)
@ -1807,6 +1863,25 @@ Miscellaneous Types
.. member:: LSCONN_ST_CLOSED
.. member:: LSCONN_ST_PEER_GOING_AWAY
.. type:: enum lsquic_hsi_flag
These flags are ORed together to specify properties of
:type:`lsxpack_header` passed to :member:`lsquic_hset_if.hsi_process_header`.
.. member:: LSQUIC_HSI_HTTP1X
Turn HTTP/1.x mode on or off. In this mode, decoded name and value
pair are separated by ``": "`` and ``"\r\n"`` is appended to the end
of the string. By default, this mode is off.
.. member:: LSQUIC_HSI_HASH_NAME
Include name hash into lsxpack_header.
.. member:: LSQUIC_HSI_HASH_NAMEVAL
Include nameval hash into lsxpack_header.
Global Variables
----------------

View File

@ -24,9 +24,9 @@ copyright = u'2020, LiteSpeed Technologies'
author = u'LiteSpeed Technologies'
# The short X.Y version
version = u'2.13'
version = u'2.14'
# The full version, including alpha/beta/rc tags
release = u'2.13.3'
release = u'2.14.0'
# -- General configuration ---------------------------------------------------

View File

@ -24,8 +24,8 @@ extern "C" {
#endif
#define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 13
#define LSQUIC_PATCH_VERSION 3
#define LSQUIC_MINOR_VERSION 14
#define LSQUIC_PATCH_VERSION 0
/**
* Engine flags:
@ -198,6 +198,7 @@ struct lsquic_stream_if {
struct ssl_ctx_st;
struct ssl_st;
struct lsxpack_header;
/**
* QUIC engine in server role needs access to certificates. This is
@ -862,6 +863,19 @@ typedef void (*lsquic_cids_update_f)(void *ctx, void **peer_ctx,
struct stack_st_X509;
enum lsquic_hsi_flag {
/**
* Turn HTTP/1.x mode on or off. In this mode, decoded name and value
* pair are separated by ": " and "\r\n" is appended to the end of the
* string. By default, this mode is off.
*/
LSQUIC_HSI_HTTP1X = 1 << 1,
/** Include name hash into lsxpack_header */
LSQUIC_HSI_HASH_NAME = 1 << 2,
/** Include nameval hash into lsxpack_header */
LSQUIC_HSI_HASH_NAMEVAL = 1 << 3,
};
struct lsquic_hset_if
{
/**
@ -869,8 +883,8 @@ struct lsquic_hset_if
* stream by calling @ref lsquic_stream_get_hset() before the stream can
* be read.
*/
void * (*hsi_create_header_set)(void *hsi_ctx,
int is_push_promise);
void * (*hsi_create_header_set)(void *hsi_ctx, lsquic_stream_t *stream,
int is_push_promise);
/**
* Return a header set prepared for decoding. If `hdr' is NULL, this
* means return a new structure with at least `space' bytes available
@ -911,6 +925,11 @@ struct lsquic_hset_if
* header sets that had an error.
*/
void (*hsi_discard_header_set)(void *hdr_set);
/**
* These flags specify properties of decoded headers passed to
* hsi_process_header().
*/
enum lsquic_hsi_flag hsi_flags;
};
/**
@ -1272,17 +1291,6 @@ lsquic_stream_writef (lsquic_stream_t *, struct lsquic_reader *);
int
lsquic_stream_flush (lsquic_stream_t *s);
/**
* @typedef lsquic_http_header_t
* @brief HTTP header structure. Contains header name and value.
*
*/
typedef struct lsquic_http_header
{
struct iovec name;
struct iovec value;
} lsquic_http_header_t;
/**
* @typedef lsquic_http_headers_t
* @brief HTTP header list structure. Contains a list of HTTP headers in key/value pairs.
@ -1291,7 +1299,7 @@ typedef struct lsquic_http_header
struct lsquic_http_headers
{
int count;
lsquic_http_header_t *headers;
struct lsxpack_header *headers;
};
/**
@ -1322,10 +1330,7 @@ lsquic_stream_get_hset (lsquic_stream_t *);
* trigger on_new_stream() event and it can be used as a regular client-
* initiated stream.
*
* If `hdr_set' is not set, it is generated by using `ea_hsi_if' callbacks.
* In either case, the header set object belongs to the connection. The
* user is not to free this object until (@ref hsi_discard_header_set) is
* called.
* `hdr_set' must be set. It is passed as-is to @lsquic_stream_get_hset.
*
* @retval 0 Stream pushed successfully.
* @retval 1 Stream push failed because it is disabled or because we hit
@ -1334,7 +1339,6 @@ lsquic_stream_get_hset (lsquic_stream_t *);
*/
int
lsquic_conn_push_stream (lsquic_conn_t *c, void *hdr_set, lsquic_stream_t *s,
const struct iovec* url, const struct iovec* authority,
const lsquic_http_headers_t *headers);
/**

View File

@ -1,6 +1,6 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
#ifndef LSXPACK_HEADER_H_v203
#define LSXPACK_HEADER_H_v203
#ifndef LSXPACK_HEADER_H_v204
#define LSXPACK_HEADER_H_v204
#ifdef __cplusplus
extern "C" {
@ -22,6 +22,8 @@ typedef uint32_t lsxpack_strlen_t;
#error unexpected LSXPACK_MAX_STRLEN
#endif
#define LSXPACK_DEL ((char *)NULL)
enum lsxpack_flag
{
LSXPACK_HPACK_IDX = 1,
@ -52,6 +54,7 @@ struct lsxpack_header
lsxpack_strlen_t name_len; /* the length of name */
lsxpack_strlen_t val_offset; /* the offset for value in the buffer */
lsxpack_strlen_t val_len; /* the length of value */
uint16_t chain_next_idx; /* mainly for cookie value chain */
uint8_t hpack_index; /* HPACK static table index */
uint8_t qpack_index; /* QPACK static table index */
uint8_t app_index; /* APP header index */
@ -77,6 +80,20 @@ lsxpack_header_set_idx(lsxpack_header_t *hdr, int hpack_idx,
}
static inline void
lsxpack_header_set_qpack_idx(lsxpack_header_t *hdr, int qpack_idx,
const char *val, size_t val_len)
{
memset(hdr, 0, sizeof(*hdr));
hdr->buf = (char *)val;
hdr->qpack_index = qpack_idx;
assert(qpack_idx != -1);
hdr->flags = LSXPACK_QPACK_IDX;
assert(val_len <= LSXPACK_MAX_STRLEN);
hdr->val_len = val_len;
}
static inline void
lsxpack_header_set_ptr(lsxpack_header_t *hdr,
const char *name, size_t name_len,
@ -162,4 +179,4 @@ lsxpack_header_get_dec_size(const lsxpack_header_t *hdr)
}
#endif
#endif //LSXPACK_HEADER_H_v203
#endif //LSXPACK_HEADER_H_v204

@ -1 +1 @@
Subproject commit d34c8c34dfb868417fbe14403f99290074341285
Subproject commit 606208599650d51f03f26afd12625c62a1be7cbb

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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)) \

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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

View File

@ -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.

View File

@ -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))

View File

@ -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,

View File

@ -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

View File

@ -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);
}

View File

@ -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
{

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -221,8 +221,6 @@ struct hset_elem
{
STAILQ_ENTRY(hset_elem) next;
struct lsxpack_header xhdr;
size_t nalloc;
char *buf;
};
@ -534,49 +532,16 @@ send_headers (lsquic_stream_ctx_t *st_h)
const char *hostname = st_h->client_ctx->hostname;
if (!hostname)
hostname = st_h->client_ctx->prog->prog_hostname;
lsquic_http_header_t headers_arr[] = {
{
.name = { .iov_base = ":method", .iov_len = 7, },
.value = { .iov_base = (void *) st_h->client_ctx->method,
.iov_len = strlen(st_h->client_ctx->method), },
},
{
.name = { .iov_base = ":scheme", .iov_len = 7, },
.value = { .iov_base = "https", .iov_len = 5, }
},
{
.name = { .iov_base = ":path", .iov_len = 5, },
.value = { .iov_base = (void *) st_h->path,
.iov_len = strlen(st_h->path), },
},
{
.name = { ":authority", 10, },
.value = { .iov_base = (void *) hostname,
.iov_len = strlen(hostname), },
},
/*
{
.name = { "host", 4 },
.value = { .iov_base = (void *) st_h->client_ctx->hostname,
.iov_len = strlen(st_h->client_ctx->hostname), },
},
*/
{
.name = { .iov_base = "user-agent", .iov_len = 10, },
.value = { .iov_base = (char *) st_h->client_ctx->prog->prog_settings.es_ua,
.iov_len = strlen(st_h->client_ctx->prog->prog_settings.es_ua), },
},
/* The following headers only gets sent if there is request payload: */
{
.name = { .iov_base = "content-type", .iov_len = 12, },
.value = { .iov_base = "application/octet-stream", .iov_len = 24, },
},
{
.name = { .iov_base = "content-length", .iov_len = 14, },
.value = { .iov_base = (void *) st_h->client_ctx->payload_size,
.iov_len = strlen(st_h->client_ctx->payload_size), },
},
};
struct lsxpack_header headers_arr[7];
#define V(v) (v), strlen(v)
lsxpack_header_set_ptr(&headers_arr[0], V(":method"), V(st_h->client_ctx->method));
lsxpack_header_set_ptr(&headers_arr[1], V(":scheme"), V("https"));
lsxpack_header_set_ptr(&headers_arr[2], V(":path"), V(st_h->path));
lsxpack_header_set_ptr(&headers_arr[3], V(":authority"), V(hostname));
lsxpack_header_set_ptr(&headers_arr[4], V("user-agent"), V(st_h->client_ctx->prog->prog_settings.es_ua));
/* The following headers only gets sent if there is request payload: */
lsxpack_header_set_ptr(&headers_arr[5], V("content-type"), V("application/octet-stream"));
lsxpack_header_set_ptr(&headers_arr[6], V("content-length"), V( st_h->client_ctx->payload_size));
lsquic_http_headers_t headers = {
.count = sizeof(headers_arr) / sizeof(headers_arr[0]),
.headers = headers_arr,
@ -983,7 +948,7 @@ verify_server_cert (void *ctx, STACK_OF(X509) *chain)
static void *
hset_create (void *hsi_ctx, int is_push_promise)
hset_create (void *hsi_ctx, lsquic_stream_t *stream, int is_push_promise)
{
struct hset *hset;
@ -1005,6 +970,7 @@ hset_prepare_decode (void *hset_p, struct lsxpack_header *xhdr,
{
struct hset *const hset = hset_p;
struct hset_elem *el;
char *buf;
if (0 == req_space)
req_space = 0x100;
@ -1018,42 +984,41 @@ hset_prepare_decode (void *hset_p, struct lsxpack_header *xhdr,
if (!xhdr)
{
buf = malloc(req_space);
if (!buf)
{
LSQ_WARN("cannot allocate buf of %zd bytes", req_space);
return NULL;
}
el = malloc(sizeof(*el));
if (!el)
{
LSQ_WARN("cannot allocate hset_elem");
free(buf);
return NULL;
}
STAILQ_INSERT_TAIL(hset, el, next);
el->buf = NULL;
el->nalloc = 0;
xhdr = &el->xhdr;
lsxpack_header_prepare_decode(&el->xhdr, buf, 0, req_space);
}
else
{
el = (struct hset_elem *) ((char *) xhdr
- offsetof(struct hset_elem, xhdr));
if (req_space <= el->nalloc)
if (req_space <= xhdr->val_len)
{
LSQ_ERROR("requested space is smaller than already allocated");
return NULL;
}
}
if (req_space > el->nalloc)
{
free(el->buf);
el->nalloc = 0;
el->buf = malloc(req_space);
if (!el->buf)
buf = realloc(el->xhdr.buf, req_space);
if (!buf)
{
LSQ_DEBUG("cannot allocate %zd bytes", req_space);
LSQ_WARN("cannot reallocate hset buf");
return NULL;
}
el->nalloc = req_space;
el->xhdr.buf = buf;
el->xhdr.val_len = req_space;
}
lsxpack_header_prepare_decode(&el->xhdr, el->buf, 0, el->nalloc);
return &el->xhdr;
}
@ -1088,7 +1053,7 @@ hset_destroy (void *hset_p)
for (el = STAILQ_FIRST(hset); el; el = next)
{
next = STAILQ_NEXT(el, next);
free(el->buf);
free(el->xhdr.buf);
free(el);
}
free(hset);
@ -1184,7 +1149,7 @@ qif_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
struct http_client_ctx *const client_ctx = stream_if_ctx;
FILE *const fh = client_ctx->qif_fh;
struct qif_stream_ctx *ctx;
struct lsquic_http_header *header;
struct lsxpack_header *header;
static int reqno;
size_t nalloc;
int i;
@ -1245,20 +1210,18 @@ qif_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
exit(1);
}
header = &ctx->headers.headers[ctx->headers.count++];
header->name.iov_base = (void *) ctx->qif_sz;
header->name.iov_len = tab - line;
header->value.iov_base = (void *) (ctx->qif_sz + (tab - line + 1));
header->value.iov_len = end - tab - 1;
lsxpack_header_set_ptr(header, (void *) ctx->qif_sz, tab - line,
(void *) (ctx->qif_sz + (tab - line + 1)), end - tab - 1);
ctx->qif_sz += end + 1 - line;
}
for (i = 0; i < ctx->headers.count; ++i)
{
ctx->headers.headers[i].name.iov_base = ctx->qif_str
+ (uintptr_t) ctx->headers.headers[i].name.iov_base;
ctx->headers.headers[i].value.iov_base = ctx->qif_str
+ (uintptr_t) ctx->headers.headers[i].value.iov_base;
ctx->headers.headers[i].buf = ctx->qif_str
+ (uintptr_t) ctx->headers.headers[i].buf;
ctx->headers.headers[i].name_ptr = ctx->qif_str
+ (uintptr_t) ctx->headers.headers[i].name_ptr;
}
lsquic_stream_wantwrite(stream, 1);

View File

@ -280,17 +280,11 @@ send_headers (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
const char *content_type;
content_type = select_content_type(st_h);
lsquic_http_header_t headers_arr[] = {
{
.name = { .iov_base = ":status", .iov_len = 7, },
.value = { .iov_base = "200", .iov_len = 3, }
},
{
.name = { .iov_base = "content-type", .iov_len = 12, },
.value = { .iov_base = (void *) content_type,
.iov_len = strlen(content_type), },
},
};
struct lsxpack_header headers_arr[2];
lsxpack_header_set_ptr(&headers_arr[0], ":status", 7, "200", 3);
lsxpack_header_set_ptr(&headers_arr[1], "content-type", 12,
content_type, strlen(content_type));
lsquic_http_headers_t headers = {
.count = sizeof(headers_arr) / sizeof(headers_arr[0]),
.headers = headers_arr,
@ -516,14 +510,47 @@ process_request (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
}
static struct hset_fm /* FM stands for Filesystem Mode */
{
unsigned id;
char *path;
} *
new_hset_fm (const char *path)
{
static unsigned hfm_id;
struct hset_fm *const hfm = malloc(sizeof(*hfm));
char *const str = strdup(path);
if (hfm && path)
{
hfm->id = hfm_id++;
hfm->path = str;
return hfm;
}
else
{
free(str);
free(hfm);
return NULL;
}
}
static void
destroy_hset_fm (struct hset_fm *hfm)
{
free(hfm->path);
free(hfm);
}
static int
push_promise (lsquic_stream_ctx_t *st_h, lsquic_stream_t *stream)
{
lsquic_conn_t *conn;
struct iovec path, host;
int s;
regex_t re;
regmatch_t matches[2];
struct hset_fm *hfm;
s = regcomp(&re, "\r\nHost: *([[:alnum:].][[:alnum:].]*)\r\n",
REG_EXTENDED|REG_ICASE);
@ -542,34 +569,39 @@ push_promise (lsquic_stream_ctx_t *st_h, lsquic_stream_t *stream)
}
regfree(&re);
host.iov_len = matches[1].rm_eo - matches[1].rm_so;
host.iov_base = st_h->req_buf + matches[1].rm_so;
path.iov_len = strlen(st_h->server_ctx->push_path);
path.iov_base = (void *) st_h->server_ctx->push_path;
hfm = new_hset_fm(st_h->server_ctx->push_path);
if (!hfm)
{
LSQ_WARN("Could not allocate hfm");
return -1;
}
#define IOV(v) { .iov_base = (v), .iov_len = sizeof(v) - 1, }
lsquic_http_header_t headers_arr[] = {
{
.name = IOV("x-some-header"),
.value = IOV("x-some-value"),
},
{
.name = IOV("x-kenny-status"),
.value = IOV("Oh my God! They killed Kenny!!! You bastards!"),
},
};
lsquic_http_headers_t extra_headers = {
#define V(v) (v), strlen(v)
struct lsxpack_header headers_arr[6];
lsxpack_header_set_ptr(&headers_arr[0], V(":method"), V("GET"));
lsxpack_header_set_ptr(&headers_arr[1], V(":path"),
V(st_h->server_ctx->push_path));
lsxpack_header_set_ptr(&headers_arr[2], V(":authority"),
st_h->req_buf + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
lsxpack_header_set_ptr(&headers_arr[3], V(":scheme"), V("https"));
lsxpack_header_set_ptr(&headers_arr[4], V("x-some-header"),
V("x-some-value"));
lsxpack_header_set_ptr(&headers_arr[5], V("x-kenny-status"),
V("Oh my God! They killed Kenny!!! You bastards!"));
lsquic_http_headers_t headers = {
.count = sizeof(headers_arr) / sizeof(headers_arr[0]),
.headers = headers_arr,
};
conn = lsquic_stream_conn(stream);
s = lsquic_conn_push_stream(conn, NULL, stream, &path, &host,
&extra_headers);
s = lsquic_conn_push_stream(conn, hfm, stream, &headers);
if (0 == s)
LSQ_NOTICE("pushed stream successfully");
else
{
destroy_hset_fm(hfm);
LSQ_ERROR("could not push stream: %s", strerror(errno));
}
return 0;
}
@ -577,7 +609,37 @@ push_promise (lsquic_stream_ctx_t *st_h, lsquic_stream_t *stream)
static void
http_server_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
http_server_on_read_pushed (struct lsquic_stream *stream,
lsquic_stream_ctx_t *st_h)
{
struct hset_fm *hfm;
hfm = lsquic_stream_get_hset(stream);
if (!hfm)
{
LSQ_ERROR("%s: error fetching hset: %s", __func__, strerror(errno));
lsquic_stream_close(stream);
return;
}
LSQ_INFO("got push request #%u for %s", hfm->id, hfm->path);
st_h->req_path = malloc(strlen(st_h->server_ctx->document_root) + 1 +
strlen(hfm->path) + 1);
strcpy(st_h->req_path, st_h->server_ctx->document_root);
strcat(st_h->req_path, "/");
strcat(st_h->req_path, hfm->path);
st_h->req_filename = strdup(st_h->req_path); /* XXX Only used for ends_with: drop it? */
process_request(stream, st_h);
free(st_h->req_buf);
lsquic_stream_shutdown(stream, 0);
destroy_hset_fm(hfm);
}
static void
http_server_on_read_regular (struct lsquic_stream *stream,
lsquic_stream_ctx_t *st_h)
{
#if HAVE_OPEN_MEMSTREAM
unsigned char buf[0x400];
@ -597,7 +659,6 @@ http_server_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
LSQ_INFO("got request: `%.*s'", (int) st_h->req_sz, st_h->req_buf);
parse_request(stream, st_h);
if (st_h->server_ctx->push_path &&
!lsquic_stream_is_pushed(stream) &&
0 != strcmp(st_h->req_path, st_h->server_ctx->push_path))
{
s = push_promise(st_h, stream);
@ -620,6 +681,16 @@ http_server_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
}
static void
http_server_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
{
if (lsquic_stream_is_pushed(stream))
http_server_on_read_pushed(stream, st_h);
else
http_server_on_read_regular(stream, st_h);
}
static void
http_server_on_close (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
{
@ -807,9 +878,9 @@ http_server_interop_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
if (!st_h->req)
ERROR_RESP(500, "Internal error: cannot fetch header set from stream");
else if (st_h->req->method == UNSET)
ERROR_RESP(400, "Method is not speicified");
ERROR_RESP(400, "Method is not specified");
else if (!st_h->req->path)
ERROR_RESP(400, "Path is not speicified");
ERROR_RESP(400, "Path is not specified");
else if (st_h->req->method == UNSUPPORTED)
ERROR_RESP(501, "Method %s is not supported", st_h->req->method_str);
else if (!(map = find_handler(st_h->req->method, st_h->req->path, matches)))
@ -979,25 +1050,11 @@ send_headers2 (struct lsquic_stream *stream, struct lsquic_stream_ctx *st_h,
snprintf(clbuf, sizeof(clbuf), "%zd", content_len);
lsquic_http_header_t headers_arr[] = {
{
.name = { .iov_base = ":status", .iov_len = 7, },
.value = { .iov_base = (char *) st_h->resp_status,
.iov_len = strlen(st_h->resp_status), },
},
{
.name = { .iov_base = "server", .iov_len = 6, },
.value = { .iov_base = LITESPEED_ID, .iov_len = sizeof(LITESPEED_ID) - 1, },
},
{
.name = { .iov_base = "content-type", .iov_len = 12, },
.value = { .iov_base = "text/html", .iov_len = 9, },
},
{
.name = { .iov_base = "content-length", .iov_len = 14, },
.value = { .iov_base = clbuf, .iov_len = strlen(clbuf), },
},
};
struct lsxpack_header headers_arr[4];
lsxpack_header_set_ptr(&headers_arr[0], V(":status"), V(st_h->resp_status));
lsxpack_header_set_ptr(&headers_arr[1], V("server"), V(LITESPEED_ID));
lsxpack_header_set_ptr(&headers_arr[2], V("content-type"), V("text/html"));
lsxpack_header_set_ptr(&headers_arr[3], V("content-length"), V(clbuf));
lsquic_http_headers_t headers = {
.count = sizeof(headers_arr) / sizeof(headers_arr[0]),
.headers = headers_arr,
@ -1042,12 +1099,39 @@ idle_size (void *lsqr_ctx)
}
static struct req *
new_req (enum method method, const char *path, const char *authority)
{
struct req *req;
req = malloc(sizeof(*req));
if (!req)
return NULL;
memset(req, 0, offsetof(struct req, decode_buf));
req->method = method;
req->path = strdup(path);
req->authority_str = strdup(authority);
if (!(req->path && req->authority_str))
{
free(req->path);
free(req->authority_str);
free(req);
return NULL;
}
return req;
}
static void
idle_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
{
struct gen_file_ctx *const gfc = &st_h->interop_u.gfc;
struct interop_push_path *push_path;
struct iovec headers[2];
struct lsxpack_header header_arr[4];
struct lsquic_http_headers headers;
struct req *req;
ssize_t nw;
if (st_h->flags & SH_HEADERS_SENT)
@ -1074,10 +1158,18 @@ idle_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
{
STAILQ_REMOVE_HEAD(&gfc->push_paths, next);
LSQ_DEBUG("pushing promise for %s", push_path->path);
headers[0] = (struct iovec) { push_path->path, strlen(push_path->path), };
headers[1] = (struct iovec) { st_h->req->authority_str, strlen(st_h->req->authority_str), };
(void) lsquic_conn_push_stream(lsquic_stream_conn(stream),
NULL, stream, &headers[0], &headers[1], NULL);
lsxpack_header_set_ptr(&header_arr[0], V(":method"), V("GET"));
lsxpack_header_set_ptr(&header_arr[1], V(":path"), V(push_path->path));
lsxpack_header_set_ptr(&header_arr[2], V(":authority"), V(st_h->req->authority_str));
lsxpack_header_set_ptr(&header_arr[3], V(":scheme"), V("https"));
headers.headers = header_arr;
headers.count = sizeof(header_arr) / sizeof(header_arr[0]);
req = new_req(GET, push_path->path, st_h->req->authority_str);
if (req)
(void) lsquic_conn_push_stream(lsquic_stream_conn(stream),
req, stream, &headers);
else
LSQ_WARN("cannot allocate req for push");
free(push_path);
}
if (0 == send_headers2(stream, st_h, gfc->remain))
@ -1173,7 +1265,8 @@ usage (const char *prog)
static void *
interop_server_hset_create (void *hsi_ctx, int is_push_promise)
interop_server_hset_create (void *hsi_ctx, lsquic_stream_t *stream,
int is_push_promise)
{
struct req *req;

View File

@ -94,7 +94,7 @@ stream_write (struct lsquic_stream *stream, struct lsquic_reader *reader)
}
#define IOV(v) { .iov_base = (v), .iov_len = sizeof(v) - 1, }
#define XHDR(name_, value_) .buf = value_, .name_ptr = name_, .val_len = sizeof(value_) - 1, .name_len = sizeof(name_) - 1
static void
@ -121,9 +121,9 @@ test_chop (unsigned max_write_sz)
#endif
0);
struct lsquic_http_header header_arr[] =
struct lsxpack_header header_arr[] =
{
{ .name = IOV(":status"), .value = IOV("302") },
{ XHDR(":status", "302") },
};
struct lsquic_http_headers headers = {

File diff suppressed because it is too large Load Diff

View File

@ -63,6 +63,7 @@ output_write (struct lsquic_stream *stream, struct lsquic_reader *reader)
#define IOV(v) { .iov_base = (v), .iov_len = sizeof(v) - 1, }
#define XHDR(name_, value_) .buf = value_, .name_ptr = name_, .val_len = sizeof(value_) - 1, .name_len = sizeof(name_) - 1
static void
@ -117,9 +118,9 @@ test_one_header (void)
0);
reset_output(0);
struct lsquic_http_header header_arr[] =
struct lsxpack_header header_arr[] =
{
{ .name = IOV(":status"), .value = IOV("302") },
{ XHDR(":status", "302") },
};
struct lsquic_http_headers headers = {
@ -169,7 +170,7 @@ test_oversize_header (void)
struct lsquic_frame_writer *fw;
int s;
struct lsquic_mm mm;
const size_t big_len = 100 * 1000;
const size_t big_len = LSXPACK_MAX_STRLEN - 20;
char *value;
lshpack_enc_init(&henc);
@ -185,12 +186,12 @@ test_oversize_header (void)
value = malloc(big_len);
memset(value, 'A', big_len);
struct lsquic_http_header header_arr[] =
struct lsxpack_header header_arr[3] =
{
{ .name = IOV(":status"), .value = IOV("302") },
{ .name = IOV("some-header"),
.value = { .iov_base = value, .iov_len = big_len, } },
{ XHDR(":status", "302") },
};
lsxpack_header_set_ptr(&header_arr[1], "some-header", 10, value, big_len);
lsxpack_header_set_ptr(&header_arr[2], "another-header", 10, value, big_len);
struct lsquic_http_headers headers = {
.count = sizeof(header_arr) / sizeof(header_arr[0]),
@ -230,10 +231,10 @@ perl tools/henc.pl :status 302 x-some-header some-value | hexdump -C
00000010 87 41 e9 2a dd c7 45 a5 |.A.*..E.|
*/
struct lsquic_http_header header_arr[] =
struct lsxpack_header header_arr[] =
{
{ .name = IOV(":status"), .value = IOV("302") },
{. name = IOV("x-some-header"), .value = IOV("some-value") },
{ XHDR(":status", "302") },
{ XHDR("x-some-header", "some-value") },
};
struct lsquic_http_headers headers = {
@ -482,10 +483,10 @@ test_errors (void)
reset_output(0);
{
struct lsquic_http_header header_arr[] =
struct lsxpack_header header_arr[] =
{
{ .name = IOV(":status"), .value = IOV("200") },
{ .name = IOV("Content-type"), .value = IOV("text/html") },
{ XHDR(":status", "200") },
{ XHDR("Content-type", "text/html") },
};
struct lsquic_http_headers headers = {
.count = 2,
@ -497,10 +498,10 @@ test_errors (void)
}
{
struct lsquic_http_header header_arr[] =
struct lsxpack_header header_arr[] =
{
{ .name = IOV(":status"), .value = IOV("200") },
{ .name = IOV("content-type"), .value = IOV("text/html") },
{ XHDR(":status", "200") },
{ XHDR("content-type", "text/html") },
};
struct lsquic_http_headers headers = {
.count = 2,
@ -549,21 +550,21 @@ perl tools/hpack.pl :method GET :path /index.html :authority www.example.com :sc
0x41, 0xe9, 0x2a, 0xdd, 0xc7, 0x45, 0xa5,
};
struct iovec path = IOV("/index.html");
struct iovec host = IOV("www.example.com");
struct lsquic_http_header header_arr[] =
struct lsxpack_header header_arr[] =
{
{ .name = IOV("x-some-header"), .value = IOV("some-value") },
{ XHDR(":method", "GET") },
{ XHDR(":path", "/index.html") },
{ XHDR(":authority", "www.example.com") },
{ XHDR(":scheme", "https") },
{ XHDR("x-some-header", "some-value") },
};
struct lsquic_http_headers headers = {
.count = 1,
.count = 5,
.headers = header_arr,
};
s = lsquic_frame_writer_write_promise(fw, 12345, 0xEEEE, &path, &host,
&headers);
s = lsquic_frame_writer_write_promise(fw, 12345, 0xEEEE, &headers);
assert(0 == s);
struct http_frame_header fh;

View File

@ -50,6 +50,7 @@
#include "lsquic_packet_out.h"
#include "lsquic_enc_sess.h"
#include "lsqpack.h"
#include "lsxpack_header.h"
#include "lsquic_frab_list.h"
#include "lsquic_qenc_hdl.h"
#include "lsquic_varint.h"
@ -501,10 +502,8 @@ test_hq_framing (int sched_immed, int dispatch_once, unsigned wsize,
* data-framing writer. This is simply so that we don't have to
* expose more stream things only for testing.
*/
struct lsquic_http_header header = {
.name = { ":method", 7, },
.value = { "GET", 3, },
};
struct lsxpack_header header;
lsxpack_header_set_ptr(&header, ":method", 7, "GET", 3);
struct lsquic_http_headers headers = { 1, &header, };
buf_in = malloc(buf_in_sz);
@ -733,10 +732,8 @@ test_frame_header_split (unsigned n_packets, unsigned extra_sz,
const unsigned wsize = 70;
const size_t buf_in_sz = wsize, buf_out_sz = 0x500000;
struct lsquic_http_header header = {
.name = { ":method", 7, },
.value = { "GET", 3, },
};
struct lsxpack_header header;
lsxpack_header_set_ptr(&header, ":method", 7, "GET", 3);
struct lsquic_http_headers headers = { 1, &header, };
buf_in = malloc(buf_in_sz);
@ -851,10 +848,8 @@ test_zero_size_frame (void)
const unsigned wsize = 7000;
const size_t buf_in_sz = wsize, buf_out_sz = 0x500000;
struct lsquic_http_header header = {
.name = { ":method", 7, },
.value = { "GET", 3, },
};
struct lsxpack_header header;
lsxpack_header_set_ptr(&header, ":method", 7, "GET", 3);
struct lsquic_http_headers headers = { 1, &header, };
buf_in = malloc(buf_in_sz);

View File

@ -151,6 +151,9 @@ static const struct conn_iface our_conn_if =
};
static struct http1x_ctor_ctx ctor_ctx = { .is_server = 0, };
static void
init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
unsigned initial_stream_window, enum stream_ctor_flags addl_ctor_flags)
@ -193,6 +196,7 @@ init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
assert(0 == s);
tobjs->conn_pub.u.ietf.qeh = &tobjs->qeh;
tobjs->conn_pub.enpub->enp_hsi_if = lsquic_http1x_if;
tobjs->conn_pub.enpub->enp_hsi_ctx = &ctor_ctx;
s = lsquic_qdh_init(&tobjs->qdh, &tobjs->lconn, 0,
tobjs->conn_pub.enpub, 0, 0);
tobjs->conn_pub.u.ietf.qdh = &tobjs->qdh;