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