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