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
22static 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
37static 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
77static 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'. */
94static 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
113static 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
126static 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
140static 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
168static 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
191static 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. */
213static 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
229static 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
307static 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. */
364static 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
380static 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. */
409static 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
442static const char hello[] = "hello, world";
443
444static 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
472static 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
491static 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
514abts_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