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
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"
19 /** Run unit tests for buffers.c */
21 test_buffers_basic(void *arg
)
26 buf_t
*buf
= NULL
, *buf2
= NULL
;
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);
43 * General pointer frobbing
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. */
64 buf_add(buf
, str
, 256);
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);
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);
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);
89 buf_add(buf
, str
, 32);
90 //test_eq(buf_capacity(buf), 256);
92 buf_add(buf
, str
, 256);
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. */
107 buf
= buf_new_with_capacity(33668);
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. */
120 buf
= buf_new_with_capacity(33668);
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);
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. */
139 buf
= buf_new_with_capacity(4096);
140 buf2
= buf_new_with_capacity(4096);
142 buf_add(buf
, str
, 255);
143 tt_int_op(buf_datalen(buf
),OP_EQ
, 25500);
144 for (j
=0;j
<100;++j
) {
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);
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);
162 buf_get_bytes(buf2
, str2
, 255);
163 tt_mem_op(str2
,OP_EQ
, str
, 255);
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));
186 /* Try adding a string too long for any freelist. */
188 char *mem
= tor_malloc_zero(65536);
190 buf_add(buf
, mem
, 65536);
193 tt_int_op(buf_datalen(buf
), OP_EQ
, 65536);
206 test_buffer_pullup(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. */
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
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
);
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);
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
);
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);
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
);
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);
299 tt_int_op(buf_get_total_allocation(), OP_EQ
, 0);
307 test_buffer_copy(void *arg
)
309 buf_t
*buf
=NULL
, *buf2
=NULL
;
319 /* Copy an empty buffer. */
320 tt_int_op(0, OP_EQ
, buf_set_to_copy(&buf2
, buf
));
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!";
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 */
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?";
351 for (i
= 0; i
< 256; ++i
) {
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
);
372 test_buffer_ext_or_cmd(void *arg
)
374 ext_or_cmd_t
*cmd
= NULL
;
375 buf_t
*buf
= buf_new();
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
);
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
);
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
);
424 /* Finally, let's try a maximum-length command. We already have the header
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
);
439 ext_or_cmd_free(cmd
);
445 test_buffer_allocation_tracking(void *arg
)
447 char *junk
= tor_malloc(16384);
448 buf_t
*buf1
= NULL
, *buf2
= NULL
;
453 crypto_rand(junk
, 16384);
454 tt_int_op(buf_get_total_allocation(), OP_EQ
, 0);
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
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);
500 tt_int_op(buf_get_total_allocation(), OP_LT
, 4008000);
501 tt_int_op(buf_get_total_allocation(), OP_EQ
, buf_allocation(buf1
));
504 tt_int_op(buf_get_total_allocation(), OP_EQ
, 0);
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;
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. */
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
);
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
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
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));
580 monotime_disable_test_mocking();
584 test_buffers_compress_fin_at_chunk_end_impl(compress_method_t method
,
585 compression_level_t level
)
588 char *contents
= NULL
;
589 char *expanded
= 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
);
620 tt_uint_op(in_len
, OP_GT
, headerjunk
);
623 tt_int_op(0, OP_EQ
, tor_uncompress(&expanded
, &out_len
,
624 contents
+ headerjunk
,
629 tt_int_op(out_len
, OP_EQ
, 0);
634 tor_compress_free(compress_state
);
641 test_buffers_compress_impl(compress_method_t method
,
642 compression_level_t level
,
643 int finalize_with_nil
)
646 char *contents
= NULL
;
647 char *expanded
= NULL
;
649 tor_compress_state_t
*compress_state
= NULL
;
650 size_t out_len
, in_len
;
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
,
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);
690 tor_compress_free(compress_state
);
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
)) {
709 compression_level_t levels
[] = {
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
);
728 static const uint8_t *tls_read_ptr
;
729 static int n_remaining
;
730 static int next_reply_val
[16];
733 mock_tls_read(tor_tls_t
*tls
, char *cp
, size_t len
)
736 int rv
= next_reply_val
[0];
738 int max
= rv
> (int)len
? (int)len
: rv
;
739 if (max
> n_remaining
)
741 memcpy(cp
, tls_read_ptr
, max
);
747 memmove(next_reply_val
, next_reply_val
+ 1, 15*sizeof(int));
752 test_buffers_tls_read_mocked(void *arg
)
758 mem
= tor_malloc(64*1024);
759 crypto_rand((char*)mem
, 64*1024);
761 n_remaining
= 64*1024;
763 MOCK(tor_tls_read
, mock_tls_read
);
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));
775 UNMOCK(tor_tls_read
);
781 test_buffers_chunk_size(void *arg
)
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);
802 test_buffers_find_contentlen(void *arg
)
804 static const struct {
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},
828 for (i
= 0; results
[i
].headers
; ++i
) {
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
);
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
);
845 test_buffer_peek_startswith(void *arg
)
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"));
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
,
878 { "time_tracking", test_buffer_time_tracking
, TT_FORK
, NULL
, NULL
},
879 { "tls_read_mocked", test_buffers_tls_read_mocked
, 0,
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" },