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