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