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