1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "abts.h"
18 #include "testutil.h"
19 #include "apr_buckets.h"
20 #include "apr_strings.h"
21 
test_create(abts_case * tc,void * data)22 static void test_create(abts_case *tc, void *data)
23 {
24     apr_bucket_alloc_t *ba;
25     apr_bucket_brigade *bb;
26 
27     ba = apr_bucket_alloc_create(p);
28     bb = apr_brigade_create(p, ba);
29 
30     ABTS_ASSERT(tc, "new brigade not NULL", bb != NULL);
31     ABTS_ASSERT(tc, "new brigade is empty", APR_BRIGADE_EMPTY(bb));
32 
33     apr_brigade_destroy(bb);
34     apr_bucket_alloc_destroy(ba);
35 }
36 
test_simple(abts_case * tc,void * data)37 static void test_simple(abts_case *tc, void *data)
38 {
39     apr_bucket_alloc_t *ba;
40     apr_bucket_brigade *bb;
41     apr_bucket *fb, *tb;
42 
43     ba = apr_bucket_alloc_create(p);
44     bb = apr_brigade_create(p, ba);
45 
46     fb = APR_BRIGADE_FIRST(bb);
47     ABTS_ASSERT(tc, "first bucket of empty brigade is sentinel",
48                 fb == APR_BRIGADE_SENTINEL(bb));
49 
50     fb = apr_bucket_flush_create(ba);
51     APR_BRIGADE_INSERT_HEAD(bb, fb);
52 
53     ABTS_ASSERT(tc, "first bucket of brigade is flush",
54                 APR_BRIGADE_FIRST(bb) == fb);
55 
56     ABTS_ASSERT(tc, "bucket after flush is sentinel",
57                 APR_BUCKET_NEXT(fb) == APR_BRIGADE_SENTINEL(bb));
58 
59     tb = apr_bucket_transient_create("aaa", 3, ba);
60     APR_BUCKET_INSERT_BEFORE(fb, tb);
61 
62     ABTS_ASSERT(tc, "bucket before flush now transient",
63                 APR_BUCKET_PREV(fb) == tb);
64     ABTS_ASSERT(tc, "bucket after transient is flush",
65                 APR_BUCKET_NEXT(tb) == fb);
66     ABTS_ASSERT(tc, "bucket before transient is sentinel",
67                 APR_BUCKET_PREV(tb) == APR_BRIGADE_SENTINEL(bb));
68 
69     apr_brigade_cleanup(bb);
70 
71     ABTS_ASSERT(tc, "cleaned up brigade was empty", APR_BRIGADE_EMPTY(bb));
72 
73     apr_brigade_destroy(bb);
74     apr_bucket_alloc_destroy(ba);
75 }
76 
make_simple_brigade(apr_bucket_alloc_t * ba,const char * first,const char * second)77 static apr_bucket_brigade *make_simple_brigade(apr_bucket_alloc_t *ba,
78                                                const char *first,
79                                                const char *second)
80 {
81     apr_bucket_brigade *bb = apr_brigade_create(p, ba);
82     apr_bucket *e;
83 
84     e = apr_bucket_transient_create(first, strlen(first), ba);
85     APR_BRIGADE_INSERT_TAIL(bb, e);
86 
87     e = apr_bucket_transient_create(second, strlen(second), ba);
88     APR_BRIGADE_INSERT_TAIL(bb, e);
89 
90     return bb;
91 }
92 
93 /* tests that 'bb' flattens to string 'expect'. */
flatten_match(abts_case * tc,const char * ctx,apr_bucket_brigade * bb,const char * expect)94 static void flatten_match(abts_case *tc, const char *ctx,
95                           apr_bucket_brigade *bb,
96                           const char *expect)
97 {
98     apr_size_t elen = strlen(expect);
99     char *buf = malloc(elen);
100     apr_size_t len = elen;
101     char msg[200];
102 
103     sprintf(msg, "%s: flatten brigade", ctx);
104     apr_assert_success(tc, msg, apr_brigade_flatten(bb, buf, &len));
105     sprintf(msg, "%s: length match (%ld not %ld)", ctx,
106             (long)len, (long)elen);
107     ABTS_ASSERT(tc, msg, len == elen);
108     sprintf(msg, "%s: result match", msg);
109     ABTS_STR_NEQUAL(tc, expect, buf, len);
110     free(buf);
111 }
112 
test_flatten(abts_case * tc,void * data)113 static void test_flatten(abts_case *tc, void *data)
114 {
115     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
116     apr_bucket_brigade *bb;
117 
118     bb = make_simple_brigade(ba, "hello, ", "world");
119 
120     flatten_match(tc, "flatten brigade", bb, "hello, world");
121 
122     apr_brigade_destroy(bb);
123     apr_bucket_alloc_destroy(ba);
124 }
125 
count_buckets(apr_bucket_brigade * bb)126 static int count_buckets(apr_bucket_brigade *bb)
127 {
128     apr_bucket *e;
129     int count = 0;
130 
131     for (e = APR_BRIGADE_FIRST(bb);
132          e != APR_BRIGADE_SENTINEL(bb);
133          e = APR_BUCKET_NEXT(e)) {
134         count++;
135     }
136 
137     return count;
138 }
139 
test_split(abts_case * tc,void * data)140 static void test_split(abts_case *tc, void *data)
141 {
142     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
143     apr_bucket_brigade *bb, *bb2;
144     apr_bucket *e;
145 
146     bb = make_simple_brigade(ba, "hello, ", "world");
147 
148     /* split at the "world" bucket */
149     e = APR_BRIGADE_LAST(bb);
150     bb2 = apr_brigade_split(bb, e);
151 
152     ABTS_ASSERT(tc, "split brigade contains one bucket",
153                 count_buckets(bb2) == 1);
154     ABTS_ASSERT(tc, "original brigade contains one bucket",
155                 count_buckets(bb) == 1);
156 
157     flatten_match(tc, "match original brigade", bb, "hello, ");
158     flatten_match(tc, "match split brigade", bb2, "world");
159 
160     apr_brigade_destroy(bb2);
161     apr_brigade_destroy(bb);
162     apr_bucket_alloc_destroy(ba);
163 }
164 
165 #define COUNT 3000
166 #define THESTR "hello"
167 
test_bwrite(abts_case * tc,void * data)168 static void test_bwrite(abts_case *tc, void *data)
169 {
170     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
171     apr_bucket_brigade *bb = apr_brigade_create(p, ba);
172     apr_off_t length;
173     int n;
174 
175     for (n = 0; n < COUNT; n++) {
176         apr_assert_success(tc, "brigade_write",
177                            apr_brigade_write(bb, NULL, NULL,
178                                              THESTR, sizeof THESTR));
179     }
180 
181     apr_assert_success(tc, "determine brigade length",
182                        apr_brigade_length(bb, 1, &length));
183 
184     ABTS_ASSERT(tc, "brigade has correct length",
185                 length == (COUNT * sizeof THESTR));
186 
187     apr_brigade_destroy(bb);
188     apr_bucket_alloc_destroy(ba);
189 }
190 
test_splitline(abts_case * tc,void * data)191 static void test_splitline(abts_case *tc, void *data)
192 {
193     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
194     apr_bucket_brigade *bin, *bout;
195 
196     bin = make_simple_brigade(ba, "blah blah blah-",
197                               "end of line.\nfoo foo foo");
198     bout = apr_brigade_create(p, ba);
199 
200     apr_assert_success(tc, "split line",
201                        apr_brigade_split_line(bout, bin,
202                                               APR_BLOCK_READ, 100));
203 
204     flatten_match(tc, "split line", bout, "blah blah blah-end of line.\n");
205     flatten_match(tc, "remainder", bin, "foo foo foo");
206 
207     apr_brigade_destroy(bout);
208     apr_brigade_destroy(bin);
209     apr_bucket_alloc_destroy(ba);
210 }
211 
212 /* Test that bucket E has content EDATA of length ELEN. */
test_bucket_content(abts_case * tc,apr_bucket * e,const char * edata,apr_size_t elen)213 static void test_bucket_content(abts_case *tc,
214                                 apr_bucket *e,
215                                 const char *edata,
216                                 apr_size_t elen)
217 {
218     const char *adata;
219     apr_size_t alen;
220 
221     apr_assert_success(tc, "read from bucket",
222                        apr_bucket_read(e, &adata, &alen,
223                                        APR_BLOCK_READ));
224 
225     ABTS_ASSERT(tc, "read expected length", alen == elen);
226     ABTS_STR_NEQUAL(tc, edata, adata, elen);
227 }
228 
test_splits(abts_case * tc,void * ctx)229 static void test_splits(abts_case *tc, void *ctx)
230 {
231     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
232     apr_bucket_brigade *bb;
233     apr_bucket *e;
234     char *str = "alphabeta";
235     int n;
236 
237     bb = apr_brigade_create(p, ba);
238 
239     APR_BRIGADE_INSERT_TAIL(bb,
240                             apr_bucket_immortal_create(str, 9, ba));
241     APR_BRIGADE_INSERT_TAIL(bb,
242                             apr_bucket_transient_create(str, 9, ba));
243     APR_BRIGADE_INSERT_TAIL(bb,
244                             apr_bucket_heap_create(strdup(str), 9, free, ba));
245     APR_BRIGADE_INSERT_TAIL(bb,
246                             apr_bucket_pool_create(apr_pstrdup(p, str), 9, p,
247                                                    ba));
248 
249     ABTS_ASSERT(tc, "four buckets inserted", count_buckets(bb) == 4);
250 
251     /* now split each of the buckets after byte 5 */
252     for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) {
253         ABTS_ASSERT(tc, "reached end of brigade",
254                     e != APR_BRIGADE_SENTINEL(bb));
255         ABTS_ASSERT(tc, "split bucket OK",
256                     apr_bucket_split(e, 5) == APR_SUCCESS);
257         e = APR_BUCKET_NEXT(e);
258         ABTS_ASSERT(tc, "split OK", e != APR_BRIGADE_SENTINEL(bb));
259         e = APR_BUCKET_NEXT(e);
260     }
261 
262     ABTS_ASSERT(tc, "four buckets split into eight",
263                 count_buckets(bb) == 8);
264 
265     for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) {
266         const char *data;
267         apr_size_t len;
268 
269         apr_assert_success(tc, "read alpha from bucket",
270                            apr_bucket_read(e, &data, &len, APR_BLOCK_READ));
271         ABTS_ASSERT(tc, "read 5 bytes", len == 5);
272         ABTS_STR_NEQUAL(tc, "alpha", data, 5);
273 
274         e = APR_BUCKET_NEXT(e);
275 
276         apr_assert_success(tc, "read beta from bucket",
277                            apr_bucket_read(e, &data, &len, APR_BLOCK_READ));
278         ABTS_ASSERT(tc, "read 4 bytes", len == 4);
279         ABTS_STR_NEQUAL(tc, "beta", data, 5);
280 
281         e = APR_BUCKET_NEXT(e);
282     }
283 
284     /* now delete the "alpha" buckets */
285     for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) {
286         apr_bucket *f;
287 
288         ABTS_ASSERT(tc, "reached end of brigade",
289                     e != APR_BRIGADE_SENTINEL(bb));
290         f = APR_BUCKET_NEXT(e);
291         apr_bucket_delete(e);
292         e = APR_BUCKET_NEXT(f);
293     }
294 
295     ABTS_ASSERT(tc, "eight buckets reduced to four",
296                 count_buckets(bb) == 4);
297 
298     flatten_match(tc, "flatten beta brigade", bb,
299                   "beta" "beta" "beta" "beta");
300 
301     apr_brigade_destroy(bb);
302     apr_bucket_alloc_destroy(ba);
303 }
304 
305 #define TIF_FNAME "testfile.txt"
306 
test_insertfile(abts_case * tc,void * ctx)307 static void test_insertfile(abts_case *tc, void *ctx)
308 {
309     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
310     apr_bucket_brigade *bb;
311     const apr_off_t bignum = (APR_INT64_C(2) << 32) + 424242;
312     apr_off_t count;
313     apr_file_t *f;
314     apr_bucket *e;
315 
316     ABTS_ASSERT(tc, "open test file",
317                 apr_file_open(&f, TIF_FNAME,
318                               APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE
319                             | APR_FOPEN_CREATE | APR_FOPEN_SPARSE,
320                               APR_OS_DEFAULT, p) == APR_SUCCESS);
321 
322     if (apr_file_trunc(f, bignum)) {
323         apr_file_close(f);
324         apr_file_remove(TIF_FNAME, p);
325         ABTS_NOT_IMPL(tc, "Skipped: could not create large file");
326         return;
327     }
328 
329     bb = apr_brigade_create(p, ba);
330 
331     e = apr_brigade_insert_file(bb, f, 0, bignum, p);
332 
333     ABTS_ASSERT(tc, "inserted file was not at end of brigade",
334                 e == APR_BRIGADE_LAST(bb));
335 
336     /* check that the total size of inserted buckets is equal to the
337      * total size of the file. */
338     count = 0;
339 
340     for (e = APR_BRIGADE_FIRST(bb);
341          e != APR_BRIGADE_SENTINEL(bb);
342          e = APR_BUCKET_NEXT(e)) {
343         ABTS_ASSERT(tc, "bucket size sane", e->length != (apr_size_t)-1);
344         count += e->length;
345     }
346 
347     ABTS_ASSERT(tc, "total size of buckets incorrect", count == bignum);
348 
349     apr_brigade_destroy(bb);
350 
351     /* Truncate the file to zero size before close() so that we don't
352      * actually write out the large file if we are on a non-sparse file
353      * system - like Mac OS X's HFS.  Otherwise, pity the poor user who
354      * has to wait for the 8GB file to be written to disk.
355      */
356     apr_file_trunc(f, 0);
357 
358     apr_file_close(f);
359     apr_bucket_alloc_destroy(ba);
360     apr_file_remove(TIF_FNAME, p);
361 }
362 
363 /* Make a test file named FNAME, and write CONTENTS to it. */
make_test_file(abts_case * tc,const char * fname,const char * contents)364 static apr_file_t *make_test_file(abts_case *tc, const char *fname,
365                                   const char *contents)
366 {
367     apr_file_t *f;
368 
369     ABTS_ASSERT(tc, "create test file",
370                 apr_file_open(&f, fname,
371                               APR_FOPEN_READ|APR_FOPEN_WRITE|APR_FOPEN_TRUNCATE|APR_FOPEN_CREATE,
372                               APR_OS_DEFAULT, p) == APR_SUCCESS);
373 
374     ABTS_ASSERT(tc, "write test file contents",
375                 apr_file_puts(contents, f) == APR_SUCCESS);
376 
377     return f;
378 }
379 
test_manyfile(abts_case * tc,void * data)380 static void test_manyfile(abts_case *tc, void *data)
381 {
382     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
383     apr_bucket_brigade *bb = apr_brigade_create(p, ba);
384     apr_file_t *f;
385 
386     f = make_test_file(tc, "manyfile.bin",
387                        "world" "hello" "brave" " ,\n");
388 
389     apr_brigade_insert_file(bb, f, 5, 5, p);
390     apr_brigade_insert_file(bb, f, 16, 1, p);
391     apr_brigade_insert_file(bb, f, 15, 1, p);
392     apr_brigade_insert_file(bb, f, 10, 5, p);
393     apr_brigade_insert_file(bb, f, 15, 1, p);
394     apr_brigade_insert_file(bb, f, 0, 5, p);
395     apr_brigade_insert_file(bb, f, 17, 1, p);
396 
397     /* can you tell what it is yet? */
398     flatten_match(tc, "file seek test", bb,
399                   "hello, brave world\n");
400 
401     apr_file_close(f);
402     apr_brigade_destroy(bb);
403     apr_bucket_alloc_destroy(ba);
404 }
405 
406 /* Regression test for PR 34708, where a file bucket will keep
407  * duplicating itself on being read() when EOF is reached
408  * prematurely. */
test_truncfile(abts_case * tc,void * data)409 static void test_truncfile(abts_case *tc, void *data)
410 {
411     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
412     apr_bucket_brigade *bb = apr_brigade_create(p, ba);
413     apr_file_t *f = make_test_file(tc, "testfile.txt", "hello");
414     apr_bucket *e;
415     const char *buf;
416     apr_size_t len;
417 
418     apr_brigade_insert_file(bb, f, 0, 5, p);
419 
420     apr_file_trunc(f, 0);
421 
422     e = APR_BRIGADE_FIRST(bb);
423 
424     ABTS_ASSERT(tc, "single bucket in brigade",
425                 APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb));
426 
427     apr_bucket_file_enable_mmap(e, 0);
428 
429     ABTS_ASSERT(tc, "read gave APR_EOF",
430                 apr_bucket_read(e, &buf, &len, APR_BLOCK_READ) == APR_EOF);
431 
432     ABTS_ASSERT(tc, "read length 0", len == 0);
433 
434     ABTS_ASSERT(tc, "still a single bucket in brigade",
435                 APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb));
436 
437     apr_file_close(f);
438     apr_brigade_destroy(bb);
439     apr_bucket_alloc_destroy(ba);
440 }
441 
442 static const char hello[] = "hello, world";
443 
test_partition(abts_case * tc,void * data)444 static void test_partition(abts_case *tc, void *data)
445 {
446     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
447     apr_bucket_brigade *bb = apr_brigade_create(p, ba);
448     apr_bucket *e;
449 
450     e = apr_bucket_immortal_create(hello, strlen(hello), ba);
451     APR_BRIGADE_INSERT_HEAD(bb, e);
452 
453     apr_assert_success(tc, "partition brigade",
454                        apr_brigade_partition(bb, 5, &e));
455 
456     test_bucket_content(tc, APR_BRIGADE_FIRST(bb),
457                         "hello", 5);
458 
459     test_bucket_content(tc, APR_BRIGADE_LAST(bb),
460                         ", world", 7);
461 
462     ABTS_ASSERT(tc, "partition returns APR_INCOMPLETE",
463                 apr_brigade_partition(bb, 8192, &e));
464 
465     ABTS_ASSERT(tc, "APR_INCOMPLETE partition returned sentinel",
466                 e == APR_BRIGADE_SENTINEL(bb));
467 
468     apr_brigade_destroy(bb);
469     apr_bucket_alloc_destroy(ba);
470 }
471 
test_write_split(abts_case * tc,void * data)472 static void test_write_split(abts_case *tc, void *data)
473 {
474     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
475     apr_bucket_brigade *bb1 = apr_brigade_create(p, ba);
476     apr_bucket_brigade *bb2;
477     apr_bucket *e;
478 
479     e = apr_bucket_heap_create(hello, strlen(hello), NULL, ba);
480     APR_BRIGADE_INSERT_HEAD(bb1, e);
481     apr_bucket_split(e, strlen("hello, "));
482     bb2 = apr_brigade_split(bb1, APR_BRIGADE_LAST(bb1));
483     apr_brigade_write(bb1, NULL, NULL, "foo", strlen("foo"));
484     test_bucket_content(tc, APR_BRIGADE_FIRST(bb2), "world", 5);
485 
486     apr_brigade_destroy(bb1);
487     apr_brigade_destroy(bb2);
488     apr_bucket_alloc_destroy(ba);
489 }
490 
test_write_putstrs(abts_case * tc,void * data)491 static void test_write_putstrs(abts_case *tc, void *data)
492 {
493     apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
494     apr_bucket_brigade *bb = apr_brigade_create(p, ba);
495     apr_bucket *e;
496     char buf[30];
497     apr_size_t len = sizeof(buf);
498     const char *expect = "123456789abcdefghij";
499 
500     e = apr_bucket_heap_create("1", 1, NULL, ba);
501     APR_BRIGADE_INSERT_HEAD(bb, e);
502 
503     apr_brigade_putstrs(bb, NULL, NULL, "2", "34", "567", "8", "9a", "bcd",
504                         "e", "f", "gh", "i", NULL);
505     apr_brigade_putstrs(bb, NULL, NULL, "j", NULL);
506     apr_assert_success(tc, "apr_brigade_flatten",
507                        apr_brigade_flatten(bb, buf, &len));
508     ABTS_STR_NEQUAL(tc, expect, buf, strlen(expect));
509 
510     apr_brigade_destroy(bb);
511     apr_bucket_alloc_destroy(ba);
512 }
513 
testbuckets(abts_suite * suite)514 abts_suite *testbuckets(abts_suite *suite)
515 {
516     suite = ADD_SUITE(suite);
517 
518     abts_run_test(suite, test_create, NULL);
519     abts_run_test(suite, test_simple, NULL);
520     abts_run_test(suite, test_flatten, NULL);
521     abts_run_test(suite, test_split, NULL);
522     abts_run_test(suite, test_bwrite, NULL);
523     abts_run_test(suite, test_splitline, NULL);
524     abts_run_test(suite, test_splits, NULL);
525     abts_run_test(suite, test_insertfile, NULL);
526     abts_run_test(suite, test_manyfile, NULL);
527     abts_run_test(suite, test_truncfile, NULL);
528     abts_run_test(suite, test_partition, NULL);
529     abts_run_test(suite, test_write_split, NULL);
530     abts_run_test(suite, test_write_putstrs, NULL);
531 
532     return suite;
533 }
534 
535 
536