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