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