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