lsquic_headers_stream.c revision 19f667fb
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * HEADERS stream logic
4 */
5
6#include <assert.h>
7#include <errno.h>
8#include <stdarg.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/queue.h>
12#ifdef MSVC
13#include <vc_compat.h>
14#endif
15
16#include "lsquic.h"
17#include "lsquic_types.h"
18#include "lsquic_int_types.h"
19#include "lsquic_frame_common.h"
20#include "lsquic_frame_reader.h"
21#include "lsquic_frame_writer.h"
22#include "lsquic_mm.h"
23#include "lsquic_engine_public.h"
24#include "lshpack.h"
25
26#include "lsquic_headers_stream.h"
27
28#define MAX_HEADERS_SIZE (64 * 1024)
29#define MAX_HEADER_TABLE_SIZE (512 * 1024)
30
31#define LSQUIC_LOGGER_MODULE LSQLM_HEADERS
32#define LSQUIC_LOG_CONN_ID lsquic_conn_id(lsquic_stream_conn(hs->hs_stream))
33#include "lsquic_logger.h"
34
35static const struct frame_reader_callbacks *frame_callbacks_ptr;
36
37struct headers_stream
38{
39    struct lsquic_stream               *hs_stream;
40    struct lsquic_frame_reader         *hs_fr;
41    struct lsquic_frame_writer         *hs_fw;
42    const struct headers_stream_callbacks
43                                       *hs_callbacks;
44    void                               *hs_cb_ctx;
45    struct lshpack_enc                  hs_henc;
46    struct lshpack_dec                  hs_hdec;
47    enum {
48            HS_IS_SERVER    = (1 << 0),
49            HS_HENC_INITED  = (1 << 1),
50    }                                   hs_flags;
51    struct lsquic_engine_public        *hs_enpub;
52#if LSQUIC_CONN_STATS
53    struct conn_stats                  *hs_conn_stats;
54#endif
55};
56
57
58int
59lsquic_headers_stream_send_settings (struct headers_stream *hs,
60        const struct lsquic_http2_setting *settings, unsigned n_settings)
61{
62    if (0 == lsquic_frame_writer_write_settings(hs->hs_fw, settings,
63                                                            n_settings))
64    {
65        lsquic_stream_wantwrite(hs->hs_stream,
66            lsquic_frame_writer_have_leftovers(hs->hs_fw));
67        return 0;
68    }
69    else
70    {
71        LSQ_WARN("Could not write settings to stream: %s",
72                                                        strerror(errno));
73        return -1;
74    }
75}
76
77
78static lsquic_stream_ctx_t *
79headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
80{
81    struct headers_stream *hs = stream_if_ctx;
82    lshpack_dec_init(&hs->hs_hdec);
83    if (0 != lshpack_enc_init(&hs->hs_henc))
84    {
85        LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno));
86        return NULL;
87    }
88    hs->hs_flags |= HS_HENC_INITED;
89    hs->hs_stream = stream;
90    LSQ_DEBUG("stream created");
91    hs->hs_fr = lsquic_frame_reader_new((hs->hs_flags & HS_IS_SERVER) ? FRF_SERVER : 0,
92                                MAX_HEADERS_SIZE, &hs->hs_enpub->enp_mm,
93                                stream, lsquic_stream_read, &hs->hs_hdec,
94                                frame_callbacks_ptr, hs,
95#if LSQUIC_CONN_STATS
96                        hs->hs_conn_stats,
97#endif
98                        hs->hs_enpub->enp_hsi_if, hs->hs_enpub->enp_hsi_ctx);
99    if (!hs->hs_fr)
100    {
101        LSQ_WARN("could not create frame reader: %s", strerror(errno));
102        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
103        return NULL;
104    }
105    hs->hs_fw = lsquic_frame_writer_new(&hs->hs_enpub->enp_mm, stream, 0,
106            &hs->hs_henc, lsquic_stream_write,
107#if LSQUIC_CONN_STATS
108            hs->hs_conn_stats,
109#endif
110            (hs->hs_flags & HS_IS_SERVER));
111    if (!hs->hs_fw)
112    {
113        LSQ_WARN("could not create frame writer: %s", strerror(errno));
114        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
115        return NULL;
116    }
117    lsquic_stream_wantread(stream, 1);
118    return (lsquic_stream_ctx_t *) hs;
119}
120
121
122static void
123headers_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *ctx)
124{
125    struct headers_stream *hs = (struct headers_stream *) ctx;
126    if (0 != lsquic_frame_reader_read(hs->hs_fr))
127    {
128        LSQ_ERROR("frame reader failed");
129        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
130    }
131}
132
133
134static void
135headers_on_write (lsquic_stream_t *stream, struct lsquic_stream_ctx *ctx)
136{
137    struct headers_stream *hs = (struct headers_stream *) ctx;
138    assert(lsquic_frame_writer_have_leftovers(hs->hs_fw));
139    int s = lsquic_frame_writer_flush(hs->hs_fw);
140    if (0 == s)
141    {
142        LSQ_DEBUG("flushed");
143        lsquic_stream_wantwrite(stream,
144            lsquic_frame_writer_have_leftovers(hs->hs_fw));
145    }
146    else
147    {
148        LSQ_WARN("Error writing to stream: %s", strerror(errno));
149        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
150    }
151}
152
153
154static void
155headers_on_close (lsquic_stream_t *stream, struct lsquic_stream_ctx *ctx)
156{
157    struct headers_stream *hs = (struct headers_stream *) ctx;
158    LSQ_DEBUG("stream closed");
159}
160
161
162int
163lsquic_headers_stream_send_headers (struct headers_stream *hs,
164    uint32_t stream_id, const struct lsquic_http_headers *headers, int eos,
165    unsigned weight)
166{
167    LSQ_DEBUG("received compressed headers to send");
168    int s;
169    s = lsquic_frame_writer_write_headers(hs->hs_fw, stream_id, headers, eos,
170                                                                        weight);
171    if (0 == s)
172    {
173        lsquic_stream_wantwrite(hs->hs_stream,
174            lsquic_frame_writer_have_leftovers(hs->hs_fw));
175    }
176    else
177        LSQ_INFO("Error writing headers: %s", strerror(errno));
178    return s;
179}
180
181
182int
183lsquic_headers_stream_send_priority (struct headers_stream *hs,
184    uint32_t stream_id, int exclusive, uint32_t dep_stream_id, unsigned weight)
185{
186    LSQ_DEBUG("received priority to send");
187    int s;
188    if (stream_id == dep_stream_id)
189    {
190        LSQ_INFO("stream cannot depend on itself"); /* RFC 7540, Sec. 5.3.1. */
191        return -1;
192    }
193    s = lsquic_frame_writer_write_priority(hs->hs_fw, stream_id, exclusive,
194                                                        dep_stream_id, weight);
195    if (0 == s)
196    {
197        lsquic_stream_wantwrite(hs->hs_stream,
198            lsquic_frame_writer_have_leftovers(hs->hs_fw));
199    }
200    else
201        LSQ_INFO("Error writing priority frame: %s", strerror(errno));
202    return s;
203}
204
205
206struct headers_stream *
207lsquic_headers_stream_new (int is_server, struct lsquic_engine_public *enpub,
208                           const struct headers_stream_callbacks *callbacks,
209#if LSQUIC_CONN_STATS
210                           struct conn_stats *conn_stats,
211#endif
212                           void *cb_ctx)
213{
214    struct headers_stream *hs = calloc(1, sizeof(*hs));
215    if (!hs)
216        return NULL;
217    hs->hs_callbacks = callbacks;
218    hs->hs_cb_ctx    = cb_ctx;
219    if (is_server)
220        hs->hs_flags = HS_IS_SERVER;
221    else
222        hs->hs_flags = 0;
223    hs->hs_enpub     = enpub;
224#if LSQUIC_CONN_STATS
225    hs->hs_conn_stats= conn_stats;
226#endif
227    return hs;
228}
229
230
231void
232lsquic_headers_stream_destroy (struct headers_stream *hs)
233{
234    if (hs->hs_fr)
235        lsquic_frame_reader_destroy(hs->hs_fr);
236    if (hs->hs_fw)
237        lsquic_frame_writer_destroy(hs->hs_fw);
238    if (hs->hs_flags & HS_HENC_INITED)
239        lshpack_enc_cleanup(&hs->hs_henc);
240    lshpack_dec_cleanup(&hs->hs_hdec);
241    free(hs);
242}
243
244
245static const struct lsquic_stream_if headers_stream_if =
246{
247    .on_new_stream = headers_on_new_stream,
248    .on_read       = headers_on_read,
249    .on_write      = headers_on_write,
250    .on_close      = headers_on_close,
251};
252
253
254const struct lsquic_stream_if *const lsquic_headers_stream_if =
255                                                &headers_stream_if;
256
257
258static void
259headers_on_incoming_headers (void *ctx, struct uncompressed_headers *uh)
260{
261    struct headers_stream *hs = ctx;
262    hs->hs_callbacks->hsc_on_headers(hs->hs_cb_ctx, uh);
263}
264
265
266static void
267headers_on_push_promise (void *ctx, struct uncompressed_headers *uh)
268{
269    struct headers_stream *hs = ctx;
270    hs->hs_callbacks->hsc_on_push_promise(hs->hs_cb_ctx, uh);
271}
272
273
274static void
275headers_on_priority (void *ctx, uint32_t stream_id, int exclusive,
276                     uint32_t dep_stream_id, unsigned weight)
277{
278    struct headers_stream *hs = ctx;
279    hs->hs_callbacks->hsc_on_priority(hs->hs_cb_ctx, stream_id, exclusive,
280                                                    dep_stream_id, weight);
281}
282
283
284static void
285headers_on_error (void *ctx, uint32_t stream_id, enum frame_reader_error err)
286{
287    struct headers_stream *hs = ctx;
288    switch (err)
289    {
290    case FR_ERR_DUPLICATE_PSEH:
291    case FR_ERR_INCOMPL_REQ_PSEH:
292    case FR_ERR_UNNEC_REQ_PSEH:
293    case FR_ERR_INCOMPL_RESP_PSEH:
294    case FR_ERR_UNNEC_RESP_PSEH:
295    case FR_ERR_UNKNOWN_PSEH:
296    case FR_ERR_UPPERCASE_HEADER:
297    case FR_ERR_MISPLACED_PSEH:
298    case FR_ERR_MISSING_PSEH:
299    case FR_ERR_DECOMPRESS:
300    case FR_ERR_HEADERS_TOO_LARGE:
301    case FR_ERR_SELF_DEP_STREAM:
302        LSQ_INFO("error %u is a stream error (stream %u)", err, stream_id);
303        hs->hs_callbacks->hsc_on_stream_error(hs->hs_cb_ctx, stream_id);
304        break;
305    case FR_ERR_INVALID_FRAME_SIZE:
306    case FR_ERR_NONZERO_STREAM_ID:
307    case FR_ERR_UNEXPECTED_PUSH:
308    case FR_ERR_ZERO_STREAM_ID:
309    case FR_ERR_NOMEM:
310    case FR_ERR_EXPECTED_CONTIN:
311        LSQ_INFO("error %u is a connection error (stream %u)", err, stream_id);
312        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
313        break;
314    }
315}
316
317
318static void
319headers_on_settings (void *ctx, uint16_t setting_id, uint32_t setting_value)
320{
321    struct headers_stream *hs = ctx;
322    switch (setting_id)
323    {
324    case SETTINGS_HEADER_TABLE_SIZE:
325        if (setting_value > MAX_HEADER_TABLE_SIZE)
326        {
327            LSQ_INFO("tried to update table size to %u, which is larger than "
328                "allowed maximum of %u bytes", setting_value,
329                MAX_HEADER_TABLE_SIZE);
330            hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
331        }
332        else
333        {
334            LSQ_INFO("update hpack table size to %u", setting_value);
335            lshpack_enc_set_max_capacity(&hs->hs_henc, setting_value);
336        }
337        break;
338    case SETTINGS_MAX_HEADER_LIST_SIZE:
339        LSQ_INFO("set max header list size to %u", setting_value);
340        lsquic_frame_writer_max_header_list_size(hs->hs_fw, setting_value);
341        break;
342    case SETTINGS_ENABLE_PUSH:
343        LSQ_INFO("got setting enable_push: %u", setting_value);
344        if (hs->hs_flags & HS_IS_SERVER)
345        {
346            if (setting_value <= 1)
347                hs->hs_callbacks->hsc_on_enable_push(hs->hs_cb_ctx,
348                                                            setting_value);
349            else
350            {
351                LSQ_INFO("invalid value of enable_push");
352                hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
353            }
354        }
355        else
356        {
357            LSQ_INFO("it is an error to receive enable_push setting in "
358                     "client mode");
359            hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
360        }
361        break;
362    case SETTINGS_MAX_CONCURRENT_STREAMS:
363    case SETTINGS_INITIAL_WINDOW_SIZE:
364    case SETTINGS_MAX_FRAME_SIZE:
365        /* [draft-ietf-quic-http-00], Section 3 */
366        LSQ_INFO("Specifying setting 0x%X is a QUIC error", setting_id);
367        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
368        break;
369    default:
370        LSQ_INFO("Ignoring unknown setting 0x%X; value 0x%X", setting_id,
371                                                                setting_value);
372        break;
373    }
374}
375
376
377int
378lsquic_headers_stream_push_promise (struct headers_stream *hs,
379                        uint32_t stream_id, uint32_t promised_stream_id,
380                        const struct iovec *path, const struct iovec *host,
381                        const struct lsquic_http_headers *headers)
382{
383    int s;
384    LSQ_DEBUG("promising stream %u in response to stream %u",
385                                            promised_stream_id, stream_id);
386    s = lsquic_frame_writer_write_promise(hs->hs_fw, stream_id,
387                                    promised_stream_id, path, host, headers);
388    if (0 == s)
389    {
390        lsquic_stream_wantwrite(hs->hs_stream,
391            lsquic_frame_writer_have_leftovers(hs->hs_fw));
392    }
393    else
394        LSQ_INFO("Error writing push promise: %s", strerror(errno));
395    return s;
396}
397
398
399size_t
400lsquic_headers_stream_mem_used (const struct headers_stream *hs)
401{
402    size_t size;
403
404    size = sizeof(*hs);
405    size += lsquic_frame_reader_mem_used(hs->hs_fr);
406    size += lsquic_frame_writer_mem_used(hs->hs_fw);
407    /* XXX: get rid of this mem_used business as we no longer use it? */
408
409    return size;
410}
411
412
413struct lsquic_stream *
414lsquic_headers_stream_get_stream (const struct headers_stream *hs)
415{
416    return hs->hs_stream;
417}
418
419
420static const struct frame_reader_callbacks frame_callbacks = {
421    .frc_on_headers      = headers_on_incoming_headers,
422    .frc_on_push_promise = headers_on_push_promise,
423    .frc_on_error        = headers_on_error,
424    .frc_on_settings     = headers_on_settings,
425    .frc_on_priority     = headers_on_priority,
426};
427
428static const struct frame_reader_callbacks *frame_callbacks_ptr = &frame_callbacks;
429
430