lsquic_headers_stream.c revision 55613f44
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 enum lshpack_dec_flags flags; 85 86 flags = 0; 87 if (hs->hs_enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HTTP1X) 88 flags |= LSHPACK_DEC_HTTP1X; 89 if (hs->hs_enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAME) 90 flags |= LSHPACK_DEC_HASH_NAME; 91 if (hs->hs_enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAMEVAL) 92 flags |= LSHPACK_DEC_HASH_NAMEVAL; 93 94 lshpack_dec_init(&hs->hs_hdec, flags); 95 if (0 != lshpack_enc_init(&hs->hs_henc)) 96 { 97 LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno)); 98 return NULL; 99 } 100 (void) lshpack_enc_use_hist(&hs->hs_henc, 1); 101 hs->hs_flags |= HS_HENC_INITED; 102 hs->hs_stream = stream; 103 LSQ_DEBUG("stream created"); 104 hs->hs_fr = lsquic_frame_reader_new((hs->hs_flags & HS_IS_SERVER) ? FRF_SERVER : 0, 105 MAX_HEADERS_SIZE, &hs->hs_enpub->enp_mm, 106 stream, lsquic_stream_read, &hs->hs_hdec, 107 frame_callbacks_ptr, hs, 108#if LSQUIC_CONN_STATS 109 hs->hs_conn_stats, 110#endif 111 hs->hs_enpub->enp_hsi_if, hs->hs_enpub->enp_hsi_ctx); 112 if (!hs->hs_fr) 113 { 114 LSQ_WARN("could not create frame reader: %s", strerror(errno)); 115 hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx); 116 return NULL; 117 } 118 hs->hs_fw = lsquic_frame_writer_new(&hs->hs_enpub->enp_mm, stream, 0, 119 &hs->hs_henc, lsquic_stream_writef, 120#if LSQUIC_CONN_STATS 121 hs->hs_conn_stats, 122#endif 123 (hs->hs_flags & HS_IS_SERVER)); 124 if (!hs->hs_fw) 125 { 126 LSQ_WARN("could not create frame writer: %s", strerror(errno)); 127 hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx); 128 return NULL; 129 } 130 lsquic_stream_wantread(stream, 1); 131 return (lsquic_stream_ctx_t *) hs; 132} 133 134 135static void 136headers_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *ctx) 137{ 138 struct headers_stream *hs = (struct headers_stream *) ctx; 139 if (0 != lsquic_frame_reader_read(hs->hs_fr)) 140 { 141 LSQ_ERROR("frame reader failed"); 142 hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx); 143 } 144} 145 146 147static void 148headers_on_write (lsquic_stream_t *stream, struct lsquic_stream_ctx *ctx) 149{ 150 struct headers_stream *hs = (struct headers_stream *) ctx; 151 assert(lsquic_frame_writer_have_leftovers(hs->hs_fw)); 152 int s = lsquic_frame_writer_flush(hs->hs_fw); 153 if (0 == s) 154 { 155 LSQ_DEBUG("flushed"); 156 lsquic_stream_wantwrite(stream, 157 lsquic_frame_writer_have_leftovers(hs->hs_fw)); 158 } 159 else 160 { 161 LSQ_WARN("Error writing to stream: %s", strerror(errno)); 162 hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx); 163 } 164} 165 166 167static void 168headers_on_close (lsquic_stream_t *stream, struct lsquic_stream_ctx *ctx) 169{ 170 struct headers_stream *hs = (struct headers_stream *) ctx; 171 LSQ_DEBUG("stream closed"); 172} 173 174 175int 176lsquic_headers_stream_send_headers (struct headers_stream *hs, 177 lsquic_stream_id_t stream_id, const struct lsquic_http_headers *headers, 178 int eos, unsigned weight) 179{ 180 LSQ_DEBUG("received compressed headers to send"); 181 int s; 182 s = lsquic_frame_writer_write_headers(hs->hs_fw, stream_id, headers, eos, 183 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 headers: %s", strerror(errno)); 191 return s; 192} 193 194 195int 196lsquic_headers_stream_send_priority (struct headers_stream *hs, 197 lsquic_stream_id_t stream_id, int exclusive, 198 lsquic_stream_id_t dep_stream_id, unsigned weight) 199{ 200 LSQ_DEBUG("received priority to send"); 201 int s; 202 if (stream_id == dep_stream_id) 203 { 204 LSQ_INFO("stream cannot depend on itself"); /* RFC 7540, Sec. 5.3.1. */ 205 return -1; 206 } 207 s = lsquic_frame_writer_write_priority(hs->hs_fw, stream_id, exclusive, 208 dep_stream_id, weight); 209 if (0 == s) 210 { 211 lsquic_stream_wantwrite(hs->hs_stream, 212 lsquic_frame_writer_have_leftovers(hs->hs_fw)); 213 } 214 else 215 LSQ_INFO("Error writing priority frame: %s", strerror(errno)); 216 return s; 217} 218 219 220struct headers_stream * 221lsquic_headers_stream_new (int is_server, struct lsquic_engine_public *enpub, 222 const struct headers_stream_callbacks *callbacks, 223#if LSQUIC_CONN_STATS 224 struct conn_stats *conn_stats, 225#endif 226 void *cb_ctx) 227{ 228 struct headers_stream *hs = calloc(1, sizeof(*hs)); 229 if (!hs) 230 return NULL; 231 hs->hs_callbacks = callbacks; 232 hs->hs_cb_ctx = cb_ctx; 233 if (is_server) 234 hs->hs_flags = HS_IS_SERVER; 235 else 236 hs->hs_flags = 0; 237 hs->hs_enpub = enpub; 238#if LSQUIC_CONN_STATS 239 hs->hs_conn_stats= conn_stats; 240#endif 241 return hs; 242} 243 244 245void 246lsquic_headers_stream_destroy (struct headers_stream *hs) 247{ 248 if (hs->hs_fr) 249 lsquic_frame_reader_destroy(hs->hs_fr); 250 if (hs->hs_fw) 251 lsquic_frame_writer_destroy(hs->hs_fw); 252 if (hs->hs_flags & HS_HENC_INITED) 253 lshpack_enc_cleanup(&hs->hs_henc); 254 lshpack_dec_cleanup(&hs->hs_hdec); 255 free(hs); 256} 257 258 259static const struct lsquic_stream_if headers_stream_if = 260{ 261 .on_new_stream = headers_on_new_stream, 262 .on_read = headers_on_read, 263 .on_write = headers_on_write, 264 .on_close = headers_on_close, 265}; 266 267 268const struct lsquic_stream_if *const lsquic_headers_stream_if = 269 &headers_stream_if; 270 271 272static void 273headers_on_incoming_headers (void *ctx, struct uncompressed_headers *uh) 274{ 275 struct headers_stream *hs = ctx; 276 hs->hs_callbacks->hsc_on_headers(hs->hs_cb_ctx, uh); 277} 278 279 280static void 281headers_on_push_promise (void *ctx, struct uncompressed_headers *uh) 282{ 283 struct headers_stream *hs = ctx; 284 hs->hs_callbacks->hsc_on_push_promise(hs->hs_cb_ctx, uh); 285} 286 287 288static void 289headers_on_priority (void *ctx, lsquic_stream_id_t stream_id, int exclusive, 290 lsquic_stream_id_t dep_stream_id, unsigned weight) 291{ 292 struct headers_stream *hs = ctx; 293 hs->hs_callbacks->hsc_on_priority(hs->hs_cb_ctx, stream_id, exclusive, 294 dep_stream_id, weight); 295} 296 297 298static void 299headers_on_error (void *ctx, lsquic_stream_id_t stream_id, 300 enum frame_reader_error err) 301{ 302 struct headers_stream *hs = ctx; 303 switch (err) 304 { 305 case FR_ERR_BAD_HEADER: 306 case FR_ERR_DECOMPRESS: 307 case FR_ERR_SELF_DEP_STREAM: 308 LSQ_INFO("error %u is a stream error (stream %"PRIu64")", err, 309 stream_id); 310 hs->hs_callbacks->hsc_on_stream_error(hs->hs_cb_ctx, stream_id); 311 break; 312 case FR_ERR_INVALID_FRAME_SIZE: 313 case FR_ERR_NONZERO_STREAM_ID: 314 case FR_ERR_UNEXPECTED_PUSH: 315 case FR_ERR_ZERO_STREAM_ID: 316 case FR_ERR_EXPECTED_CONTIN: 317 case FR_ERR_OTHER_ERROR: 318 LSQ_INFO("error %u is a connection error (stream %"PRIu64")", err, 319 stream_id); 320 hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx); 321 break; 322 } 323} 324 325 326static void 327headers_on_settings (void *ctx, uint16_t setting_id, uint32_t setting_value) 328{ 329 struct headers_stream *hs = ctx; 330 switch (setting_id) 331 { 332 case SETTINGS_HEADER_TABLE_SIZE: 333 if (setting_value > MAX_HEADER_TABLE_SIZE) 334 { 335 LSQ_INFO("tried to update table size to %u, which is larger than " 336 "allowed maximum of %u bytes", setting_value, 337 MAX_HEADER_TABLE_SIZE); 338 hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx); 339 } 340 else 341 { 342 LSQ_INFO("update hpack table size to %u", setting_value); 343 lshpack_enc_set_max_capacity(&hs->hs_henc, setting_value); 344 } 345 break; 346 case SETTINGS_MAX_HEADER_LIST_SIZE: 347 LSQ_INFO("set max header list size to %u", setting_value); 348 lsquic_frame_writer_max_header_list_size(hs->hs_fw, setting_value); 349 break; 350 case SETTINGS_ENABLE_PUSH: 351 LSQ_INFO("got setting enable_push: %u", setting_value); 352 if (hs->hs_flags & HS_IS_SERVER) 353 { 354 if (setting_value <= 1) 355 hs->hs_callbacks->hsc_on_enable_push(hs->hs_cb_ctx, 356 setting_value); 357 else 358 { 359 LSQ_INFO("invalid value of enable_push"); 360 hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx); 361 } 362 } 363 else 364 { 365 LSQ_INFO("it is an error to receive enable_push setting in " 366 "client mode"); 367 hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx); 368 } 369 break; 370 case SETTINGS_MAX_CONCURRENT_STREAMS: 371 case SETTINGS_INITIAL_WINDOW_SIZE: 372 case SETTINGS_MAX_FRAME_SIZE: 373 /* [draft-ietf-quic-http-00], Section 3 */ 374 LSQ_INFO("Specifying setting 0x%X is a QUIC error", setting_id); 375 hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx); 376 break; 377 default: 378 LSQ_INFO("Ignoring unknown setting 0x%X; value 0x%X", setting_id, 379 setting_value); 380 break; 381 } 382} 383 384 385int 386lsquic_headers_stream_push_promise (struct headers_stream *hs, 387 lsquic_stream_id_t stream_id64, lsquic_stream_id_t promised_stream_id64, 388 const struct lsquic_http_headers *headers) 389{ 390 uint32_t stream_id = stream_id64; 391 uint32_t promised_stream_id = promised_stream_id64; 392 int s; 393 LSQ_DEBUG("promising stream %u in response to stream %u", 394 promised_stream_id, stream_id); 395 s = lsquic_frame_writer_write_promise(hs->hs_fw, stream_id, 396 promised_stream_id, headers); 397 if (0 == s) 398 { 399 lsquic_stream_wantwrite(hs->hs_stream, 400 lsquic_frame_writer_have_leftovers(hs->hs_fw)); 401 } 402 else 403 LSQ_INFO("Error writing push promise: %s", strerror(errno)); 404 return s; 405} 406 407 408size_t 409lsquic_headers_stream_mem_used (const struct headers_stream *hs) 410{ 411 size_t size; 412 413 size = sizeof(*hs); 414 size += lsquic_frame_reader_mem_used(hs->hs_fr); 415 size += lsquic_frame_writer_mem_used(hs->hs_fw); 416 /* XXX: does not cover HPACK encoder and HPACK decoder */ 417 418 return size; 419} 420 421 422struct lsquic_stream * 423lsquic_headers_stream_get_stream (const struct headers_stream *hs) 424{ 425 return hs->hs_stream; 426} 427 428 429static const struct frame_reader_callbacks frame_callbacks = { 430 .frc_on_headers = headers_on_incoming_headers, 431 .frc_on_push_promise = headers_on_push_promise, 432 .frc_on_error = headers_on_error, 433 .frc_on_settings = headers_on_settings, 434 .frc_on_priority = headers_on_priority, 435}; 436 437static const struct frame_reader_callbacks *frame_callbacks_ptr = &frame_callbacks; 438 439