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