test_hcsi_reader.c revision 55d69529
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <assert.h> 3#include <inttypes.h> 4#include <stdlib.h> 5#include <string.h> 6#include <stdio.h> 7#include <sys/queue.h> 8 9#include "lsquic.h" 10#include "lsquic_int_types.h" 11#include "lsquic_varint.h" 12#include "lsquic_hq.h" 13#include "lsquic_hcsi_reader.h" 14#include "lsquic_hash.h" 15#include "lsquic_conn.h" 16 17struct test 18{ 19 int lineno; 20 21 enum { 22 TEST_NO_FLAGS = 0, 23 TEST_NUL_OUT_LEST_FULL = 1 << 0, 24 } flags; 25 26 unsigned char input[0x100]; 27 size_t input_sz; 28 29 int retval; 30 char output[0x1000]; 31}; 32 33 34static const struct test tests[] = 35{ 36 { 37 __LINE__, 38 TEST_NO_FLAGS, 39 { 40 0x03, 41 0x04, 42 0x80, 0x12, 0x34, 0x45, 43 }, 44 6, 45 0, 46 "on_cancel_push: 1193029\n", 47 }, 48 49 { 50 __LINE__, 51 TEST_NO_FLAGS, 52 { 53 HQFT_MAX_PUSH_ID, 54 0x02, 55 0x41, 0x23, 56 }, 57 4, 58 0, 59 "on_max_push_id: 291\n", 60 }, 61 62 { 63 __LINE__, 64 TEST_NO_FLAGS, 65 { 66 HQFT_SETTINGS, 67 0x00, 68 }, 69 2, 70 0, 71 "have SETTINGS frame\n", 72 }, 73 74 { /* Frame contents do not match frame length */ 75 __LINE__, 76 TEST_NO_FLAGS, 77 { 78 HQFT_MAX_PUSH_ID, 79 0x03, 80 0x41, 0x23, 81 }, 82 4, 83 -1, 84 "", 85 }, 86 87 { 88 __LINE__, 89 TEST_NO_FLAGS, 90 { 91 HQFT_SETTINGS, 92 13, 93 0x52, 0x34, 94 0xC0, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 95 0x52, 0x35, 96 0x00, 97 }, 98 15, 99 0, 100 "on_setting: 0x1234=0x12233445566778\n" 101 "on_setting: 0x1235=0x0\n" 102 "have SETTINGS frame\n" 103 , 104 }, 105 106 { 107 __LINE__, 108 TEST_NO_FLAGS, 109 { 110 0x80, 0x0F, 0x07, 0x00, /* HQFT_PRIORITY_UPDATE_STREAM */ 111 7, 112 0x52, 0x34, 113 0x41, 0x42, 0x43, 0x44, 0x45, /* ABCDE */ 114 HQFT_MAX_PUSH_ID, 115 0x02, 116 0x41, 0x23, 117 }, 118 16, 119 0, 120 "on_priority_update: stream=0x1234, [ABCDE]\n" 121 "on_max_push_id: 291\n" 122 , 123 }, 124 125 { 126 __LINE__, 127 TEST_NO_FLAGS, 128 { 129 0x80, 0x0F, 0x07, 0x01, /* HQFT_PRIORITY_UPDATE_PUSH */ 130 6, 131 0x08, 132 0x50, 0x51, 0x52, 0x53, 0x54, /* PQRST */ 133 }, 134 11, 135 0, 136 "on_priority_update: push=0x8, [PQRST]\n" 137 , 138 }, 139 140 { 141 __LINE__, 142 TEST_NUL_OUT_LEST_FULL, 143 { 144 0x80, 0x0F, 0x07, 0x01, /* HQFT_PRIORITY_UPDATE_PUSH */ 145 21, 146 0x08, 147 0x50, 0x51, 0x52, 0x53, 0x54, /* PQRST */ 148 0x50, 0x51, 0x52, 0x53, 0x54, /* PQRST */ 149 0x50, 0x51, 0x52, 0x53, 0x54, /* PQRST */ 150 0x50, 0x51, 0x52, 0x53, 0x54, /* PQRST */ 151 }, 152 26, 153 0, 154 "on_priority_update: push=0x8, [PQRSTPQRSTPQRSTPQRST]\n" 155 , 156 }, 157 158}; 159 160 161static void 162on_cancel_push (void *ctx, uint64_t push_id) 163{ 164 fprintf(ctx, "%s: %"PRIu64"\n", __func__, push_id); 165} 166 167static void 168on_max_push_id (void *ctx, uint64_t push_id) 169{ 170 fprintf(ctx, "%s: %"PRIu64"\n", __func__, push_id); 171} 172 173static void 174on_settings_frame (void *ctx) 175{ 176 fprintf(ctx, "have SETTINGS frame\n"); 177} 178 179static void 180on_setting (void *ctx, uint64_t setting_id, uint64_t value) 181{ 182 fprintf(ctx, "%s: 0x%"PRIX64"=0x%"PRIX64"\n", __func__, setting_id, value); 183} 184 185static void 186on_goaway (void *ctx, uint64_t stream_id) 187{ 188 fprintf(ctx, "%s: %"PRIu64"\n", __func__, stream_id); 189} 190 191static void 192on_frame_error (void *ctx, unsigned code, uint64_t frame_type) 193{ 194 fprintf(ctx, "%s: %"PRIu64"\n", __func__, frame_type); 195} 196 197static void 198on_priority_update (void *ctx, enum hq_frame_type frame_type, 199 /* PFV: Priority Field Value */ 200 uint64_t id, const char *pfv, size_t pfv_sz) 201{ 202 const char *type; 203 204 switch (frame_type) 205 { 206 case HQFT_PRIORITY_UPDATE_STREAM: type = "stream"; break; 207 case HQFT_PRIORITY_UPDATE_PUSH: type = "push"; break; 208 default: assert(0); return; 209 } 210 211 fprintf(ctx, "%s: %s=0x%"PRIX64", [%.*s]\n", __func__, type, id, 212 (int) pfv_sz, pfv); 213} 214 215static const struct hcsi_callbacks callbacks = 216{ 217 .on_cancel_push = on_cancel_push, 218 .on_max_push_id = on_max_push_id, 219 .on_settings_frame = on_settings_frame, 220 .on_setting = on_setting, 221 .on_goaway = on_goaway, 222 .on_frame_error = on_frame_error, 223 .on_priority_update = on_priority_update, 224}; 225 226 227static void 228abort_error (struct lsquic_conn *conn, int is_app, unsigned error_code, 229 const char *format, ...) 230{ 231} 232 233 234static const struct conn_iface conn_iface = { 235 .ci_abort_error = abort_error, 236}; 237 238 239static void 240run_test (const struct test *test) 241{ 242 struct hcsi_reader reader; 243 size_t read_sz, out_sz, toread; 244 FILE *out_f; 245 char *output; 246 const unsigned char *p; 247 int s; 248 struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0); 249 lconn.cn_if = &conn_iface; 250 251 for (read_sz = 1; read_sz <= test->input_sz; ++read_sz) 252 { 253 out_f = open_memstream(&output, &out_sz); 254 lsquic_hcsi_reader_init(&reader, &lconn, &callbacks, out_f); 255 reader.hr_flag |= HR_FLAG_RCVD_SETTING; 256 257 p = test->input; 258 do 259 { 260 toread = test->input + test->input_sz - p; 261 if (toread > read_sz) 262 toread = read_sz; 263 s = lsquic_hcsi_reader_feed(&reader, p, toread); 264 if (s != 0) 265 break; 266 p += toread; 267 } 268 while (p < test->input + test->input_sz); 269 270 assert(s == test->retval); 271 272 fclose(out_f); 273 if (test->retval == 0 && read_sz < test->input_sz 274 && (test->flags & TEST_NUL_OUT_LEST_FULL)) 275 assert(0 == strcmp(output, "")); 276 else 277 assert(0 == strcmp(test->output, output)); 278 free(output); 279 } 280} 281 282int 283main (void) 284{ 285 const struct test *test; 286 struct test coalesced_test; 287 288 for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test) 289 run_test(test); 290 291 memset(&coalesced_test, 0, sizeof(coalesced_test)); 292 for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test) 293 if (test->retval == 0 && !(test->flags & TEST_NUL_OUT_LEST_FULL)) 294 { 295 memcpy(coalesced_test.input + coalesced_test.input_sz, 296 test->input, test->input_sz); 297 coalesced_test.input_sz += test->input_sz; 298 strcat(coalesced_test.output, test->output); 299 } 300 run_test(&coalesced_test); 301 302 return 0; 303} 304