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,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.
|
||||
|
|
103
docs/apiref.rst
103
docs/apiref.rst
|
@ -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
|
||||
----------------
|
||||
|
||||
|
|
|
@ -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 ---------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue