Merge branch 'maint-0.4.5' into release-0.4.5
[tor.git] / src / test / test_buffers.c
blobfbaa628fd7b14ac0718a2097ea60dc9c361fe797
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2020, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
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"
18 /** Run unit tests for buffers.c */
19 static void
20 test_buffers_basic(void *arg)
22 char str[256];
23 char str2[256];
25 buf_t *buf = NULL, *buf2 = NULL;
26 const char *cp;
28 int j;
29 size_t r;
30 (void) arg;
32 /****
33 * buf_new
34 ****/
35 if (!(buf = buf_new()))
36 TT_DIE(("Assertion failed."));
38 //test_eq(buf_capacity(buf), 4096);
39 tt_int_op(buf_datalen(buf),OP_EQ, 0);
41 /****
42 * General pointer frobbing
44 for (j=0;j<256;++j) {
45 str[j] = (char)j;
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));
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);
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);
75 tt_int_op(buf_datalen(buf),OP_EQ, 0);
76 buf_free(buf);
77 buf = NULL;
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]);
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);
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);
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);
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);
123 for (j=0; j < 20; ++j) {
124 buf_get_bytes(buf, str2, 255);
125 tt_mem_op(str2,OP_EQ, str, 255);
127 for (j=0;j<80;++j) {
128 buf_add(buf, str, 255);
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);
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);
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);
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);
164 buf_free(buf);
165 buf_free(buf2);
166 buf = buf2 = NULL;
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;
185 /* Try adding a string too long for any freelist. */
187 char *mem = tor_malloc_zero(65536);
188 buf = buf_new();
189 buf_add(buf, mem, 65536);
190 tor_free(mem);
192 tt_int_op(buf_datalen(buf), OP_EQ, 65536);
193 buf_free(buf);
194 buf = NULL;
197 done:
198 if (buf)
199 buf_free(buf);
200 if (buf2)
201 buf_free(buf2);
204 static void
205 test_buffer_pullup(void *arg)
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);
215 buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
217 tt_assert(buf);
218 tt_int_op(buf_get_default_chunk_size(buf), OP_EQ, 4096);
220 tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
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);
228 /* Let's make sure nothing got allocated */
229 tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
231 /* Case 1: everything puts into the first chunk with some moving. */
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);
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);
254 buf_free(buf);
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);
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);
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);
282 buf_free(buf);
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);
295 buf_free(buf);
296 buf = NULL;
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);
305 static void
306 test_buffers_move_all(void *arg)
308 (void)arg;
309 buf_t *input = buf_new();
310 buf_t *output = buf_new();
311 char *s = NULL;
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);
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);
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);
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");
362 done:
363 buf_free(output);
364 buf_free(input);
365 tor_free(s);
368 static void
369 test_buffer_copy(void *arg)
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;
378 buf = buf_new();
379 tt_assert(buf);
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));
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);
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);
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);
426 done:
427 if (buf)
428 buf_free(buf);
429 if (buf2)
430 buf_free(buf2);
433 static void
434 test_buffer_allocation_tracking(void *arg)
436 char *junk = tor_malloc(16384);
437 buf_t *buf1 = NULL, *buf2 = NULL;
438 int i;
440 (void)arg;
442 crypto_rand(junk, 16384);
443 tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
445 buf1 = buf_new();
446 tt_assert(buf1);
447 buf2 = buf_new();
448 tt_assert(buf2);
450 tt_int_op(buf_allocation(buf1), OP_EQ, 0);
451 tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
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 */
461 tt_int_op(buf_get_total_allocation(), OP_EQ, 16384);
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 */
466 tt_int_op(buf_get_total_allocation(), OP_EQ, 12288); /* that chunk was really
467 freed. */
469 buf_add(buf2, junk, 4000);
470 tt_int_op(buf_allocation(buf2), OP_EQ, 4096); /* another 4k chunk. */
472 * We bounce back up to 16384 by allocating a new chunk.
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. */
480 /* Make a really huge buffer */
481 for (i = 0; i < 1000; ++i) {
482 buf_add(buf2, junk, 4000);
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;
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);
495 done:
496 buf_free(buf1);
497 buf_free(buf2);
498 tor_free(junk);
501 static void
502 test_buffer_time_tracking(void *arg)
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;
511 crypto_rand(tmp, sizeof(tmp));
513 monotime_enable_test_mocking();
515 buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
516 tt_assert(buf);
518 monotime_coarse_set_mock_time_nsec(START_NSEC);
519 const uint32_t START_TS = monotime_coarse_get_stamp();
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));
525 buf_add(buf, "ABCDEFG", 7);
526 tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_TS+1000));
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));
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));
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));
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));
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));
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));
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));
568 done:
569 buf_free(buf);
570 buf_free(buf2);
571 monotime_disable_test_mocking();
574 static void
575 test_buffers_compress_fin_at_chunk_end_impl(compress_method_t method,
576 compression_level_t level)
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;
586 buf = buf_new_with_capacity(128); /* will round up */
587 sz = buf_get_default_chunk_size(buf);
588 msg = tor_malloc_zero(sz);
590 buf_add(buf, msg, 1);
591 tt_assert(buf->head);
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);
603 in_len = buf_datalen(buf);
604 contents = tor_malloc(in_len);
606 tt_int_op(buf_get_bytes(buf, contents, in_len), OP_EQ, 0);
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);
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));
620 tt_int_op(out_len, OP_EQ, 0);
621 tt_assert(expanded);
623 done:
624 buf_free(buf);
625 tor_compress_free(compress_state);
626 tor_free(contents);
627 tor_free(expanded);
628 tor_free(msg);
631 static void
632 test_buffers_compress_impl(compress_method_t method,
633 compression_level_t level,
634 int finalize_with_nil)
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;
644 buf = buf_new_with_capacity(128); /* will round up */
645 compress_state = tor_compress_new(1, method, level);
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);
662 in_len = buf_datalen(buf);
663 contents = tor_malloc(in_len);
665 tt_int_op(buf_get_bytes(buf, contents, in_len), OP_EQ, 0);
667 tt_int_op(0, OP_EQ, tor_uncompress(&expanded, &out_len,
668 contents, in_len,
669 method, 1,
670 LOG_WARN));
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);
679 done:
680 buf_free(buf);
681 tor_compress_free(compress_state);
682 tor_free(contents);
683 tor_free(expanded);
684 tor_free(msg);
687 static void
688 test_buffers_compress(void *arg)
690 const char *methodname = arg;
691 tt_assert(methodname);
693 compress_method_t method = compression_method_get_by_name(methodname);
694 tt_int_op(method, OP_NE, UNKNOWN_METHOD);
696 if (! tor_compress_supports_method(method)) {
697 tt_skip();
700 compression_level_t levels[] = {
701 BEST_COMPRESSION,
702 HIGH_COMPRESSION,
703 MEDIUM_COMPRESSION,
704 LOW_COMPRESSION
707 for (unsigned l = 0; l < ARRAY_LENGTH(levels); ++l) {
708 compression_level_t level = levels[l];
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);
715 done:
719 static const uint8_t *tls_read_ptr;
720 static int n_remaining;
721 static int next_reply_val[16];
723 static int
724 mock_tls_read(tor_tls_t *tls, char *cp, size_t len)
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;
738 memmove(next_reply_val, next_reply_val + 1, 15*sizeof(int));
739 return rv;
742 static void
743 test_buffers_tls_read_mocked(void *arg)
745 uint8_t *mem;
746 buf_t *buf;
747 (void)arg;
749 mem = tor_malloc(64*1024);
750 crypto_rand((char*)mem, 64*1024);
751 tls_read_ptr = mem;
752 n_remaining = 64*1024;
754 MOCK(tor_tls_read, mock_tls_read);
756 buf = buf_new();
758 next_reply_val[0] = 1024;
759 tt_int_op(128, OP_EQ, buf_read_from_tls(buf, NULL, 128));
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));
765 done:
766 UNMOCK(tor_tls_read);
767 tor_free(mem);
768 buf_free(buf);
771 static void
772 test_buffers_chunk_size(void *arg)
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:
792 static void
793 test_buffers_find_contentlen(void *arg)
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 }
815 int i;
817 (void)arg;
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);
831 done:
835 static void
836 test_buffer_peek_startswith(void *arg)
838 (void)arg;
839 buf_t *buf;
840 buf = buf_new();
841 tt_ptr_op(buf, OP_NE, NULL);
843 tt_assert(buf_peek_startswith(buf, ""));
844 tt_assert(! buf_peek_startswith(buf, "X"));
846 buf_add(buf, "Tor", 3);
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"));
857 done:
858 buf_free(buf);
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 },
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" },
886 END_OF_TESTCASES