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