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