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