test_buffers.c (25512B)
1 /* Copyright (c) 2001-2004, Roger Dingledine. 2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 3 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 4 /* See LICENSE for licensing information */ 5 6 #define BUFFERS_PRIVATE 7 #define PROTO_HTTP_PRIVATE 8 #include "core/or/or.h" 9 #include "lib/buf/buffers.h" 10 #include "lib/tls/buffers_tls.h" 11 #include "lib/tls/tortls.h" 12 #include "lib/compress/compress.h" 13 #include "lib/crypt_ops/crypto_rand.h" 14 #include "core/proto/proto_http.h" 15 #include "core/proto/proto_socks.h" 16 #include "test/test.h" 17 18 /** Run unit tests for buffers.c */ 19 static void 20 test_buffers_basic(void *arg) 21 { 22 char str[256]; 23 char str2[256]; 24 25 buf_t *buf = NULL, *buf2 = NULL; 26 const char *cp; 27 28 int j; 29 size_t r; 30 (void) arg; 31 32 /**** 33 * buf_new 34 ****/ 35 if (!(buf = buf_new())) 36 TT_DIE(("Assertion failed.")); 37 38 //test_eq(buf_capacity(buf), 4096); 39 tt_int_op(buf_datalen(buf),OP_EQ, 0); 40 41 /**** 42 * General pointer frobbing 43 */ 44 for (j=0;j<256;++j) { 45 str[j] = (char)j; 46 } 47 buf_add(buf, str, 256); 48 buf_add(buf, str, 256); 49 tt_int_op(buf_datalen(buf),OP_EQ, 512); 50 buf_get_bytes(buf, str2, 200); 51 tt_mem_op(str,OP_EQ, str2, 200); 52 tt_int_op(buf_datalen(buf),OP_EQ, 312); 53 memset(str2, 0, sizeof(str2)); 54 55 buf_get_bytes(buf, str2, 256); 56 tt_mem_op(str+200,OP_EQ, str2, 56); 57 tt_mem_op(str,OP_EQ, str2+56, 200); 58 tt_int_op(buf_datalen(buf),OP_EQ, 56); 59 memset(str2, 0, sizeof(str2)); 60 /* Okay, now we should be 512 bytes into the 4096-byte buffer. If we add 61 * another 3584 bytes, we hit the end. */ 62 for (j=0;j<15;++j) { 63 buf_add(buf, str, 256); 64 } 65 buf_assert_ok(buf); 66 tt_int_op(buf_datalen(buf),OP_EQ, 3896); 67 buf_get_bytes(buf, str2, 56); 68 tt_int_op(buf_datalen(buf),OP_EQ, 3840); 69 tt_mem_op(str+200,OP_EQ, str2, 56); 70 for (j=0;j<15;++j) { 71 memset(str2, 0, sizeof(str2)); 72 buf_get_bytes(buf, str2, 256); 73 tt_mem_op(str,OP_EQ, str2, 256); 74 } 75 tt_int_op(buf_datalen(buf),OP_EQ, 0); 76 buf_free(buf); 77 buf = NULL; 78 79 /* Okay, now make sure growing can work. */ 80 buf = buf_new_with_capacity(16); 81 //test_eq(buf_capacity(buf), 16); 82 buf_add(buf, str+1, 255); 83 //test_eq(buf_capacity(buf), 256); 84 buf_get_bytes(buf, str2, 254); 85 tt_mem_op(str+1,OP_EQ, str2, 254); 86 //test_eq(buf_capacity(buf), 256); 87 buf_assert_ok(buf); 88 buf_add(buf, str, 32); 89 //test_eq(buf_capacity(buf), 256); 90 buf_assert_ok(buf); 91 buf_add(buf, str, 256); 92 buf_assert_ok(buf); 93 //test_eq(buf_capacity(buf), 512); 94 tt_int_op(buf_datalen(buf),OP_EQ, 33+256); 95 buf_get_bytes(buf, str2, 33); 96 tt_int_op(*str2,OP_EQ, str[255]); 97 98 tt_mem_op(str2+1,OP_EQ, str, 32); 99 //test_eq(buf_capacity(buf), 512); 100 tt_int_op(buf_datalen(buf),OP_EQ, 256); 101 buf_get_bytes(buf, str2, 256); 102 tt_mem_op(str,OP_EQ, str2, 256); 103 104 /* now try shrinking: case 1. */ 105 buf_free(buf); 106 buf = buf_new_with_capacity(33668); 107 for (j=0;j<67;++j) { 108 buf_add(buf, str,255); 109 } 110 //test_eq(buf_capacity(buf), 33668); 111 tt_int_op(buf_datalen(buf),OP_EQ, 17085); 112 for (j=0; j < 40; ++j) { 113 buf_get_bytes(buf, str2, 255); 114 tt_mem_op(str2,OP_EQ, str, 255); 115 } 116 117 /* now try shrinking: case 2. */ 118 buf_free(buf); 119 buf = buf_new_with_capacity(33668); 120 for (j=0;j<67;++j) { 121 buf_add(buf, str, 255); 122 } 123 for (j=0; j < 20; ++j) { 124 buf_get_bytes(buf, str2, 255); 125 tt_mem_op(str2,OP_EQ, str, 255); 126 } 127 for (j=0;j<80;++j) { 128 buf_add(buf, str, 255); 129 } 130 //test_eq(buf_capacity(buf),33668); 131 for (j=0; j < 120; ++j) { 132 buf_get_bytes(buf, str2, 255); 133 tt_mem_op(str2,OP_EQ, str, 255); 134 } 135 136 /* Move from buf to buf. */ 137 buf_free(buf); 138 buf = buf_new_with_capacity(4096); 139 buf2 = buf_new_with_capacity(4096); 140 for (j=0;j<100;++j) 141 buf_add(buf, str, 255); 142 tt_int_op(buf_datalen(buf),OP_EQ, 25500); 143 for (j=0;j<100;++j) { 144 r = 10; 145 buf_move_to_buf(buf2, buf, &r); 146 tt_int_op(r,OP_EQ, 0); 147 } 148 tt_int_op(buf_datalen(buf),OP_EQ, 24500); 149 tt_int_op(buf_datalen(buf2),OP_EQ, 1000); 150 for (j=0;j<3;++j) { 151 buf_get_bytes(buf2, str2, 255); 152 tt_mem_op(str2,OP_EQ, str, 255); 153 } 154 r = 8192; /*big move*/ 155 buf_move_to_buf(buf2, buf, &r); 156 tt_int_op(r,OP_EQ, 0); 157 r = 30000; /* incomplete move */ 158 buf_move_to_buf(buf2, buf, &r); 159 tt_int_op(r,OP_EQ, 13692); 160 for (j=0;j<97;++j) { 161 buf_get_bytes(buf2, str2, 255); 162 tt_mem_op(str2,OP_EQ, str, 255); 163 } 164 buf_free(buf); 165 buf_free(buf2); 166 buf = buf2 = NULL; 167 168 buf = buf_new_with_capacity(5); 169 cp = "Testing. This is a moderately long Testing string."; 170 for (j = 0; cp[j]; j++) 171 buf_add(buf, cp+j, 1); 172 tt_int_op(0,OP_EQ, buf_find_string_offset(buf, "Testing", 7)); 173 tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "esting", 6)); 174 tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "est", 3)); 175 tt_int_op(39,OP_EQ, buf_find_string_offset(buf, "ing str", 7)); 176 tt_int_op(35,OP_EQ, buf_find_string_offset(buf, "Testing str", 11)); 177 tt_int_op(32,OP_EQ, buf_find_string_offset(buf, "ng ", 3)); 178 tt_int_op(43,OP_EQ, buf_find_string_offset(buf, "string.", 7)); 179 tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "shrdlu", 6)); 180 tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "Testing thing", 13)); 181 tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "ngx", 3)); 182 buf_free(buf); 183 buf = NULL; 184 185 /* Try adding a string too long for any freelist. */ 186 { 187 char *mem = tor_malloc_zero(65536); 188 buf = buf_new(); 189 buf_add(buf, mem, 65536); 190 tor_free(mem); 191 192 tt_int_op(buf_datalen(buf), OP_EQ, 65536); 193 buf_free(buf); 194 buf = NULL; 195 } 196 197 done: 198 if (buf) 199 buf_free(buf); 200 if (buf2) 201 buf_free(buf2); 202 } 203 204 static void 205 test_buffer_pullup(void *arg) 206 { 207 buf_t *buf; 208 char *stuff, *tmp; 209 const char *cp; 210 size_t sz; 211 (void)arg; 212 stuff = tor_malloc(16384); 213 tmp = tor_malloc(16384); 214 215 buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ 216 217 tt_assert(buf); 218 tt_int_op(buf_get_default_chunk_size(buf), OP_EQ, 4096); 219 220 tt_int_op(buf_get_total_allocation(), OP_EQ, 0); 221 222 /* There are a bunch of cases for pullup. One is the trivial case. Let's 223 mess around with an empty buffer. */ 224 buf_pullup(buf, 16, &cp, &sz); 225 tt_ptr_op(cp, OP_EQ, NULL); 226 tt_uint_op(sz, OP_EQ, 0); 227 228 /* Let's make sure nothing got allocated */ 229 tt_int_op(buf_get_total_allocation(), OP_EQ, 0); 230 231 /* Case 1: everything puts into the first chunk with some moving. */ 232 233 /* Let's add some data. */ 234 crypto_rand(stuff, 16384); 235 buf_add(buf, stuff, 3000); 236 buf_add(buf, stuff+3000, 3000); 237 buf_pullup(buf, 0, &cp, &sz); 238 tt_ptr_op(cp, OP_NE, NULL); 239 tt_int_op(sz, OP_LE, 4096); 240 241 /* Make room for 3000 bytes in the first chunk, so that the pullup-move code 242 * can get tested. */ 243 tt_int_op(buf_get_bytes(buf, tmp, 3000), OP_EQ, 3000); 244 tt_mem_op(tmp,OP_EQ, stuff, 3000); 245 buf_pullup(buf, 2048, &cp, &sz); 246 buf_assert_ok(buf); 247 tt_ptr_op(cp, OP_NE, NULL); 248 tt_int_op(sz, OP_GE, 2048); 249 tt_mem_op(cp,OP_EQ, stuff+3000, 2048); 250 tt_int_op(3000, OP_EQ, buf_datalen(buf)); 251 tt_int_op(buf_get_bytes(buf, tmp, 3000), OP_EQ, 0); 252 tt_mem_op(tmp,OP_EQ, stuff+3000, 2048); 253 254 buf_free(buf); 255 256 /* Now try the large-chunk case. */ 257 buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ 258 buf_add(buf, stuff, 4000); 259 buf_add(buf, stuff+4000, 4000); 260 buf_add(buf, stuff+8000, 4000); 261 buf_add(buf, stuff+12000, 4000); 262 tt_int_op(buf_datalen(buf), OP_EQ, 16000); 263 buf_pullup(buf, 0, &cp, &sz); 264 tt_ptr_op(cp, OP_NE, NULL); 265 tt_int_op(sz, OP_LE, 4096); 266 267 buf_pullup(buf, 12500, &cp, &sz); 268 buf_assert_ok(buf); 269 tt_ptr_op(cp, OP_NE, NULL); 270 tt_int_op(sz, OP_GE, 12500); 271 tt_mem_op(cp,OP_EQ, stuff, 12500); 272 tt_int_op(buf_datalen(buf), OP_EQ, 16000); 273 274 buf_get_bytes(buf, tmp, 12400); 275 tt_mem_op(tmp,OP_EQ, stuff, 12400); 276 tt_int_op(buf_datalen(buf), OP_EQ, 3600); 277 buf_get_bytes(buf, tmp, 3500); 278 tt_mem_op(tmp,OP_EQ, stuff+12400, 3500); 279 buf_get_bytes(buf, tmp, 100); 280 tt_mem_op(tmp,OP_EQ, stuff+15900, 10); 281 282 buf_free(buf); 283 284 /* Make sure that the pull-up-whole-buffer case works */ 285 buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ 286 buf_add(buf, stuff, 4000); 287 buf_add(buf, stuff+4000, 4000); 288 buf_get_bytes(buf, tmp, 100); /* dump 100 bytes from first chunk */ 289 buf_pullup(buf, 16000, &cp, &sz); 290 buf_assert_ok(buf); 291 tt_ptr_op(cp, OP_NE, NULL); 292 tt_int_op(sz, OP_EQ, 7900); 293 tt_mem_op(cp,OP_EQ, stuff+100, 7900); 294 295 buf_free(buf); 296 buf = NULL; 297 298 tt_int_op(buf_get_total_allocation(), OP_EQ, 0); 299 done: 300 buf_free(buf); 301 tor_free(stuff); 302 tor_free(tmp); 303 } 304 305 static void 306 test_buffers_move_all(void *arg) 307 { 308 (void)arg; 309 buf_t *input = buf_new(); 310 buf_t *output = buf_new(); 311 char *s = NULL; 312 313 /* Move from empty buffer to nonempty buffer. (This is a regression test for 314 * #40076) */ 315 buf_add(output, "abc", 3); 316 buf_assert_ok(input); 317 buf_assert_ok(output); 318 buf_move_all(output, input); 319 buf_assert_ok(input); 320 buf_assert_ok(output); 321 tt_int_op(buf_datalen(output), OP_EQ, 3); 322 s = buf_extract(output, NULL); 323 tt_str_op(s, OP_EQ, "abc"); 324 buf_free(output); 325 buf_free(input); 326 tor_free(s); 327 328 /* Move from empty to empty. */ 329 output = buf_new(); 330 input = buf_new(); 331 buf_move_all(output, input); 332 buf_assert_ok(input); 333 buf_assert_ok(output); 334 tt_int_op(buf_datalen(output), OP_EQ, 0); 335 buf_free(output); 336 buf_free(input); 337 338 /* Move from nonempty to empty. */ 339 output = buf_new(); 340 input = buf_new(); 341 buf_add(input, "longstanding bugs", 17); 342 buf_move_all(output, input); 343 buf_assert_ok(input); 344 buf_assert_ok(output); 345 s = buf_extract(output, NULL); 346 tt_str_op(s, OP_EQ, "longstanding bugs"); 347 buf_free(output); 348 buf_free(input); 349 tor_free(s); 350 351 /* Move from nonempty to nonempty. */ 352 output = buf_new(); 353 input = buf_new(); 354 buf_add(output, "the start of", 12); 355 buf_add(input, " a string", 9); 356 buf_move_all(output, input); 357 buf_assert_ok(input); 358 buf_assert_ok(output); 359 s = buf_extract(output, NULL); 360 tt_str_op(s, OP_EQ, "the start of a string"); 361 362 done: 363 buf_free(output); 364 buf_free(input); 365 tor_free(s); 366 } 367 368 static void 369 test_buffer_copy(void *arg) 370 { 371 buf_t *buf=NULL, *buf2=NULL; 372 const char *s; 373 size_t len; 374 char b[256]; 375 int i; 376 (void)arg; 377 378 buf = buf_new(); 379 tt_assert(buf); 380 381 /* Copy an empty buffer. */ 382 tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf)); 383 tt_assert(buf2); 384 tt_int_op(0, OP_EQ, buf_datalen(buf2)); 385 386 /* Now try with a short buffer. */ 387 s = "And now comes an act of enormous enormance!"; 388 len = strlen(s); 389 buf_add(buf, s, len); 390 tt_int_op(len, OP_EQ, buf_datalen(buf)); 391 /* Add junk to buf2 so we can test replacing.*/ 392 buf_add(buf2, "BLARG", 5); 393 tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf)); 394 tt_int_op(len, OP_EQ, buf_datalen(buf2)); 395 buf_get_bytes(buf2, b, len); 396 tt_mem_op(b, OP_EQ, s, len); 397 /* Now free buf2 and retry so we can test allocating */ 398 buf_free(buf2); 399 buf2 = NULL; 400 tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf)); 401 tt_int_op(len, OP_EQ, buf_datalen(buf2)); 402 buf_get_bytes(buf2, b, len); 403 tt_mem_op(b, OP_EQ, s, len); 404 /* Clear buf for next test */ 405 buf_get_bytes(buf, b, len); 406 tt_int_op(buf_datalen(buf),OP_EQ,0); 407 408 /* Okay, now let's try a bigger buffer. */ 409 s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit " 410 "esse quam nihil molestiae consequatur, vel illum qui dolorem eum " 411 "fugiat quo voluptas nulla pariatur?"; 412 len = strlen(s); 413 for (i = 0; i < 256; ++i) { 414 b[0]=i; 415 buf_add(buf, b, 1); 416 buf_add(buf, s, len); 417 } 418 tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf)); 419 tt_int_op(buf_datalen(buf2), OP_EQ, buf_datalen(buf)); 420 for (i = 0; i < 256; ++i) { 421 buf_get_bytes(buf2, b, len+1); 422 tt_int_op((unsigned char)b[0],OP_EQ,i); 423 tt_mem_op(b+1, OP_EQ, s, len); 424 } 425 426 done: 427 if (buf) 428 buf_free(buf); 429 if (buf2) 430 buf_free(buf2); 431 } 432 433 static void 434 test_buffer_allocation_tracking(void *arg) 435 { 436 char *junk = tor_malloc(16384); 437 buf_t *buf1 = NULL, *buf2 = NULL; 438 int i; 439 440 (void)arg; 441 442 crypto_rand(junk, 16384); 443 tt_int_op(buf_get_total_allocation(), OP_EQ, 0); 444 445 buf1 = buf_new(); 446 tt_assert(buf1); 447 buf2 = buf_new(); 448 tt_assert(buf2); 449 450 tt_int_op(buf_allocation(buf1), OP_EQ, 0); 451 tt_int_op(buf_get_total_allocation(), OP_EQ, 0); 452 453 buf_add(buf1, junk, 4000); 454 buf_add(buf1, junk, 4000); 455 buf_add(buf1, junk, 4000); 456 buf_add(buf1, junk, 4000); 457 tt_int_op(buf_allocation(buf1), OP_EQ, 16384); 458 buf_get_bytes(buf1, junk, 100); 459 tt_int_op(buf_allocation(buf1), OP_EQ, 16384); /* still 4 4k chunks */ 460 461 tt_int_op(buf_get_total_allocation(), OP_EQ, 16384); 462 463 buf_get_bytes(buf1, junk, 4096); /* drop a 1k chunk... */ 464 tt_int_op(buf_allocation(buf1), OP_EQ, 3*4096); /* now 3 4k chunks */ 465 466 tt_int_op(buf_get_total_allocation(), OP_EQ, 12288); /* that chunk was really 467 freed. */ 468 469 buf_add(buf2, junk, 4000); 470 tt_int_op(buf_allocation(buf2), OP_EQ, 4096); /* another 4k chunk. */ 471 /* 472 * We bounce back up to 16384 by allocating a new chunk. 473 */ 474 tt_int_op(buf_get_total_allocation(), OP_EQ, 16384); 475 buf_add(buf2, junk, 4000); 476 tt_int_op(buf_allocation(buf2), OP_EQ, 8192); /* another 4k chunk. */ 477 tt_int_op(buf_get_total_allocation(), 478 OP_EQ, 5*4096); /* that chunk was new. */ 479 480 /* Make a really huge buffer */ 481 for (i = 0; i < 1000; ++i) { 482 buf_add(buf2, junk, 4000); 483 } 484 tt_int_op(buf_allocation(buf2), OP_GE, 4008000); 485 tt_int_op(buf_get_total_allocation(), OP_GE, 4008000); 486 buf_free(buf2); 487 buf2 = NULL; 488 489 tt_int_op(buf_get_total_allocation(), OP_LT, 4008000); 490 tt_int_op(buf_get_total_allocation(), OP_EQ, buf_allocation(buf1)); 491 buf_free(buf1); 492 buf1 = NULL; 493 tt_int_op(buf_get_total_allocation(), OP_EQ, 0); 494 495 done: 496 buf_free(buf1); 497 buf_free(buf2); 498 tor_free(junk); 499 } 500 501 static void 502 test_buffer_time_tracking(void *arg) 503 { 504 buf_t *buf=NULL, *buf2=NULL; 505 const time_t START = 1389288246; 506 const uint64_t START_NSEC = ((uint64_t)START) * 1000000000; 507 int i; 508 char tmp[4096]; 509 (void)arg; 510 511 crypto_rand(tmp, sizeof(tmp)); 512 513 monotime_enable_test_mocking(); 514 515 buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */ 516 tt_assert(buf); 517 518 monotime_coarse_set_mock_time_nsec(START_NSEC); 519 const uint32_t START_TS = monotime_coarse_get_stamp(); 520 521 /* Empty buffer means the timestamp is 0. */ 522 tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS)); 523 tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+1000)); 524 525 buf_add(buf, "ABCDEFG", 7); 526 tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+1000)); 527 528 buf2 = buf_copy(buf); 529 tt_assert(buf2); 530 tt_int_op(1234, OP_EQ, 531 buf_get_oldest_chunk_timestamp(buf2, START_TS+1234)); 532 533 /* Now add more bytes; enough to overflow the first chunk. */ 534 monotime_coarse_set_mock_time_nsec(START_NSEC + 123 * (uint64_t)1000000); 535 const uint32_t TS2 = monotime_coarse_get_stamp(); 536 for (i = 0; i < 600; ++i) 537 buf_add(buf, "ABCDEFG", 7); 538 tt_int_op(4207, OP_EQ, buf_datalen(buf)); 539 540 /* The oldest bytes are still in the front. */ 541 tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+2000)); 542 543 /* Once those bytes are dropped, the chunk is still on the first 544 * timestamp. */ 545 buf_get_bytes(buf, tmp, 100); 546 tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+2000)); 547 548 /* But once we discard the whole first chunk, we get the data in the second 549 * chunk. */ 550 buf_get_bytes(buf, tmp, 4000); 551 tt_int_op(107, OP_EQ, buf_datalen(buf)); 552 tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS2+2000)); 553 554 /* This time we'll be grabbing a chunk from the freelist, and making sure 555 its time gets updated */ 556 monotime_coarse_set_mock_time_nsec(START_NSEC + 5617 * (uint64_t)1000000); 557 const uint32_t TS3 = monotime_coarse_get_stamp(); 558 for (i = 0; i < 600; ++i) 559 buf_add(buf, "ABCDEFG", 7); 560 tt_int_op(4307, OP_EQ, buf_datalen(buf)); 561 562 tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS2+2000)); 563 buf_get_bytes(buf, tmp, 4000); 564 buf_get_bytes(buf, tmp, 306); 565 tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS3)); 566 tt_int_op(383, OP_EQ, buf_get_oldest_chunk_timestamp(buf, TS3+383)); 567 568 done: 569 buf_free(buf); 570 buf_free(buf2); 571 monotime_disable_test_mocking(); 572 } 573 574 static void 575 test_buffers_compress_fin_at_chunk_end_impl(compress_method_t method, 576 compression_level_t level) 577 { 578 char *msg = NULL; 579 char *contents = NULL; 580 char *expanded = NULL; 581 buf_t *buf = NULL; 582 tor_compress_state_t *compress_state = NULL; 583 size_t out_len, in_len; 584 size_t sz, headerjunk; 585 586 buf = buf_new_with_capacity(128); /* will round up */ 587 sz = buf_get_default_chunk_size(buf); 588 msg = tor_malloc_zero(sz); 589 590 buf_add(buf, msg, 1); 591 tt_assert(buf->head); 592 593 /* Fill up the chunk so the compression stuff won't fit in one chunk. */ 594 tt_uint_op(buf->head->memlen, OP_LT, sz); 595 headerjunk = buf->head->memlen - 7; 596 buf_add(buf, msg, headerjunk-1); 597 tt_uint_op(buf->head->datalen, OP_EQ, headerjunk); 598 tt_uint_op(buf_datalen(buf), OP_EQ, headerjunk); 599 /* Write an empty string, with finalization on. */ 600 compress_state = tor_compress_new(1, method, level); 601 tt_int_op(buf_add_compress(buf, compress_state, "", 0, 1), OP_EQ, 0); 602 603 in_len = buf_datalen(buf); 604 contents = tor_malloc(in_len); 605 606 tt_int_op(buf_get_bytes(buf, contents, in_len), OP_EQ, 0); 607 608 if (method == NO_METHOD) { 609 tt_uint_op(in_len, OP_EQ, headerjunk); 610 } else { 611 tt_uint_op(in_len, OP_GT, headerjunk); 612 } 613 614 tt_int_op(0, OP_EQ, tor_uncompress(&expanded, &out_len, 615 contents + headerjunk, 616 in_len - headerjunk, 617 method, 1, 618 LOG_WARN)); 619 620 tt_int_op(out_len, OP_EQ, 0); 621 tt_assert(expanded); 622 623 done: 624 buf_free(buf); 625 tor_compress_free(compress_state); 626 tor_free(contents); 627 tor_free(expanded); 628 tor_free(msg); 629 } 630 631 static void 632 test_buffers_compress_impl(compress_method_t method, 633 compression_level_t level, 634 int finalize_with_nil) 635 { 636 char *msg = NULL; 637 char *contents = NULL; 638 char *expanded = NULL; 639 buf_t *buf = NULL; 640 tor_compress_state_t *compress_state = NULL; 641 size_t out_len, in_len; 642 int done; 643 644 buf = buf_new_with_capacity(128); /* will round up */ 645 compress_state = tor_compress_new(1, method, level); 646 647 msg = tor_malloc(512); 648 crypto_rand(msg, 512); 649 tt_int_op(buf_add_compress(buf, compress_state, 650 msg, 128, 0), OP_EQ, 0); 651 tt_int_op(buf_add_compress(buf, compress_state, 652 msg+128, 128, 0), OP_EQ, 0); 653 tt_int_op(buf_add_compress(buf, compress_state, 654 msg+256, 256, 0), OP_EQ, 0); 655 done = !finalize_with_nil; 656 tt_int_op(buf_add_compress(buf, compress_state, 657 "all done", 9, done), OP_EQ, 0); 658 if (finalize_with_nil) { 659 tt_int_op(buf_add_compress(buf, compress_state, "", 0, 1), OP_EQ, 0); 660 } 661 662 in_len = buf_datalen(buf); 663 contents = tor_malloc(in_len); 664 665 tt_int_op(buf_get_bytes(buf, contents, in_len), OP_EQ, 0); 666 667 tt_int_op(0, OP_EQ, tor_uncompress(&expanded, &out_len, 668 contents, in_len, 669 method, 1, 670 LOG_WARN)); 671 672 tt_int_op(out_len, OP_GE, 128); 673 tt_mem_op(msg, OP_EQ, expanded, 128); 674 tt_int_op(out_len, OP_GE, 512); 675 tt_mem_op(msg, OP_EQ, expanded, 512); 676 tt_int_op(out_len, OP_EQ, 512+9); 677 tt_mem_op("all done", OP_EQ, expanded+512, 9); 678 679 done: 680 buf_free(buf); 681 tor_compress_free(compress_state); 682 tor_free(contents); 683 tor_free(expanded); 684 tor_free(msg); 685 } 686 687 static void 688 test_buffers_compress(void *arg) 689 { 690 const char *methodname = arg; 691 tt_assert(methodname); 692 693 compress_method_t method = compression_method_get_by_name(methodname); 694 tt_int_op(method, OP_NE, UNKNOWN_METHOD); 695 696 if (! tor_compress_supports_method(method)) { 697 tt_skip(); 698 } 699 700 compression_level_t levels[] = { 701 BEST_COMPRESSION, 702 HIGH_COMPRESSION, 703 MEDIUM_COMPRESSION, 704 LOW_COMPRESSION 705 }; 706 707 for (unsigned l = 0; l < ARRAY_LENGTH(levels); ++l) { 708 compression_level_t level = levels[l]; 709 710 test_buffers_compress_impl(method, level, 0); 711 test_buffers_compress_impl(method, level, 1); 712 test_buffers_compress_fin_at_chunk_end_impl(method, level); 713 } 714 715 done: 716 ; 717 } 718 719 static const uint8_t *tls_read_ptr; 720 static int n_remaining; 721 static int next_reply_val[16]; 722 723 static int 724 mock_tls_read(tor_tls_t *tls, char *cp, size_t len) 725 { 726 (void)tls; 727 int rv = next_reply_val[0]; 728 if (rv > 0) { 729 int max = rv > (int)len ? (int)len : rv; 730 if (max > n_remaining) 731 max = n_remaining; 732 memcpy(cp, tls_read_ptr, max); 733 rv = max; 734 n_remaining -= max; 735 tls_read_ptr += max; 736 } 737 738 memmove(next_reply_val, next_reply_val + 1, 15*sizeof(int)); 739 return rv; 740 } 741 742 static void 743 test_buffers_tls_read_mocked(void *arg) 744 { 745 uint8_t *mem; 746 buf_t *buf; 747 (void)arg; 748 749 mem = tor_malloc(64*1024); 750 crypto_rand((char*)mem, 64*1024); 751 tls_read_ptr = mem; 752 n_remaining = 64*1024; 753 754 MOCK(tor_tls_read, mock_tls_read); 755 756 buf = buf_new(); 757 758 next_reply_val[0] = 1024; 759 tt_int_op(128, OP_EQ, buf_read_from_tls(buf, NULL, 128)); 760 761 next_reply_val[0] = 5000; 762 next_reply_val[1] = 5000; 763 tt_int_op(6000, OP_EQ, buf_read_from_tls(buf, NULL, 6000)); 764 765 done: 766 UNMOCK(tor_tls_read); 767 tor_free(mem); 768 buf_free(buf); 769 } 770 771 static void 772 test_buffers_chunk_size(void *arg) 773 { 774 (void)arg; 775 const int min = 256; 776 const int max = 65536; 777 tt_uint_op(buf_preferred_chunk_size(3), OP_EQ, min); 778 tt_uint_op(buf_preferred_chunk_size(25), OP_EQ, min); 779 tt_uint_op(buf_preferred_chunk_size(0), OP_EQ, min); 780 tt_uint_op(buf_preferred_chunk_size(256), OP_EQ, 512); 781 tt_uint_op(buf_preferred_chunk_size(65400), OP_EQ, max); 782 /* Here, we're implicitly saying that the chunk header overhead is 783 * between 1 and 100 bytes. 24..48 would probably be more accurate. */ 784 tt_uint_op(buf_preferred_chunk_size(65536), OP_GT, 65536); 785 tt_uint_op(buf_preferred_chunk_size(65536), OP_LT, 65536+100); 786 tt_uint_op(buf_preferred_chunk_size(165536), OP_GT, 165536); 787 tt_uint_op(buf_preferred_chunk_size(165536), OP_LT, 165536+100); 788 done: 789 ; 790 } 791 792 static void 793 test_buffers_find_contentlen(void *arg) 794 { 795 static const struct { 796 const char *headers; 797 int r; 798 int contentlen; 799 } results[] = { 800 { "Blah blah\r\nContent-Length: 1\r\n\r\n", 1, 1 }, 801 { "Blah blah\r\n\r\n", 0, 0 }, /* no content-len */ 802 { "Blah blah Content-Length: 1\r\n", 0, 0 }, /* no content-len. */ 803 { "Blah blah\r\nContent-Length: 100000\r\n", 1, 100000}, 804 { "Blah blah\r\nContent-Length: 1000000000000000000000000\r\n", -1, 0}, 805 { "Blah blah\r\nContent-Length: 0\r\n", 1, 0}, 806 { "Blah blah\r\nContent-Length: -1\r\n", -1, 0}, 807 { "Blah blah\r\nContent-Length: 1x\r\n", -1, 0}, 808 { "Blah blah\r\nContent-Length: 1 x\r\n", -1, 0}, 809 { "Blah blah\r\nContent-Length: 1 \r\n", 1, 1}, 810 { "Blah blah\r\nContent-Length: \r\n", -1, 0}, 811 { "Blah blah\r\nContent-Length: ", -1, 0}, 812 { "Blah blah\r\nContent-Length: 5050", -1, 0}, 813 { NULL, 0, 0 } 814 }; 815 int i; 816 817 (void)arg; 818 819 for (i = 0; results[i].headers; ++i) { 820 int r; 821 size_t sz; 822 size_t headerlen = strlen(results[i].headers); 823 char * tmp = tor_memdup(results[i].headers, headerlen);/* ensure no eos */ 824 sz = 999; /* to ensure it gets set */ 825 r = buf_http_find_content_length(tmp, headerlen, &sz); 826 tor_free(tmp); 827 log_debug(LD_DIR, "%d: %s", i, escaped(results[i].headers)); 828 tt_int_op(r, OP_EQ, results[i].r); 829 tt_int_op(sz, OP_EQ, results[i].contentlen); 830 } 831 done: 832 ; 833 } 834 835 static void 836 test_buffer_peek_startswith(void *arg) 837 { 838 (void)arg; 839 buf_t *buf; 840 buf = buf_new(); 841 tt_ptr_op(buf, OP_NE, NULL); 842 843 tt_assert(buf_peek_startswith(buf, "")); 844 tt_assert(! buf_peek_startswith(buf, "X")); 845 846 buf_add(buf, "Tor", 3); 847 848 tt_assert(buf_peek_startswith(buf, "")); 849 tt_assert(buf_peek_startswith(buf, "T")); 850 tt_assert(buf_peek_startswith(buf, "To")); 851 tt_assert(buf_peek_startswith(buf, "Tor")); 852 tt_assert(! buf_peek_startswith(buf, "Top")); 853 tt_assert(! buf_peek_startswith(buf, "For")); 854 tt_assert(! buf_peek_startswith(buf, "Tork")); 855 tt_assert(! buf_peek_startswith(buf, "Torpor")); 856 857 done: 858 buf_free(buf); 859 } 860 861 struct testcase_t buffer_tests[] = { 862 { "basic", test_buffers_basic, TT_FORK, NULL, NULL }, 863 { "copy", test_buffer_copy, TT_FORK, NULL, NULL }, 864 { "pullup", test_buffer_pullup, TT_FORK, NULL, NULL }, 865 { "move_all", test_buffers_move_all, 0, NULL, NULL }, 866 { "startswith", test_buffer_peek_startswith, 0, NULL, NULL }, 867 { "allocation_tracking", test_buffer_allocation_tracking, TT_FORK, 868 NULL, NULL }, 869 { "time_tracking", test_buffer_time_tracking, TT_FORK, NULL, NULL }, 870 { "tls_read_mocked", test_buffers_tls_read_mocked, 0, 871 NULL, NULL }, 872 { "chunk_size", test_buffers_chunk_size, 0, NULL, NULL }, 873 { "find_contentlen", test_buffers_find_contentlen, 0, NULL, NULL }, 874 875 { "compress/zlib", test_buffers_compress, TT_FORK, 876 &passthrough_setup, (char*)"deflate" }, 877 { "compress/gzip", test_buffers_compress, TT_FORK, 878 &passthrough_setup, (char*)"gzip" }, 879 { "compress/zstd", test_buffers_compress, TT_FORK, 880 &passthrough_setup, (char*)"x-zstd" }, 881 { "compress/lzma", test_buffers_compress, TT_FORK, 882 &passthrough_setup, (char*)"x-tor-lzma" }, 883 { "compress/none", test_buffers_compress, TT_FORK, 884 &passthrough_setup, (char*)"identity" }, 885 886 END_OF_TESTCASES 887 };