1 /* 2 * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <openssl/bio.h> 11 #include "testutil.h" 12 13 static const char *filename = NULL; 14 15 /* 16 * Test that a BIO_f_readbuffer() with a BIO_new_file() behaves nicely if 17 * BIO_gets() and BIO_read_ex() are both called. 18 * Since the BIO_gets() calls buffer the reads, the BIO_read_ex() should 19 * still be able to read the buffered data if we seek back to the start. 20 * 21 * The following cases are tested using tstid: 22 * 0 : Just use BIO_read_ex(). 23 * 1 : Try a few reads using BIO_gets() before using BIO_read_ex() 24 * 2 : Read the entire file using BIO_gets() before using BIO_read_ex(). 25 */ 26 static int test_readbuffer_file_bio(int tstid) 27 { 28 int ret = 0, len, partial; 29 BIO *in = NULL, *in_bio = NULL, *readbuf_bio = NULL; 30 char buf[255]; 31 char expected[4096]; 32 size_t readbytes = 0, bytes = 0, count = 0; 33 34 /* Open a file BIO and read all the data */ 35 if (!TEST_ptr(in = BIO_new_file(filename, "r")) 36 || !TEST_int_eq(BIO_read_ex(in, expected, sizeof(expected), 37 &readbytes), 38 1) 39 || !TEST_int_lt(readbytes, sizeof(expected))) 40 goto err; 41 BIO_free(in); 42 in = NULL; 43 44 /* Create a new file bio that sits under a readbuffer BIO */ 45 if (!TEST_ptr(readbuf_bio = BIO_new(BIO_f_readbuffer())) 46 || !TEST_ptr(in_bio = BIO_new_file(filename, "r"))) 47 goto err; 48 49 in_bio = BIO_push(readbuf_bio, in_bio); 50 readbuf_bio = NULL; 51 52 if (!TEST_int_eq(BIO_tell(in_bio), 0)) 53 goto err; 54 55 if (tstid != 0) { 56 partial = 4; 57 while (!BIO_eof(in_bio)) { 58 len = BIO_gets(in_bio, buf, sizeof(buf)); 59 if (len == 0) { 60 if (!TEST_true(BIO_eof(in_bio))) 61 goto err; 62 } else { 63 if (!TEST_int_gt(len, 0) 64 || !TEST_int_le(len, (int)sizeof(buf) - 1)) 65 goto err; 66 if (!TEST_true(buf[len] == 0)) 67 goto err; 68 if (len > 1 69 && !BIO_eof(in_bio) 70 && len != ((int)sizeof(buf) - 1) 71 && !TEST_true(buf[len - 1] == '\n')) 72 goto err; 73 } 74 if (tstid == 1 && --partial == 0) 75 break; 76 } 77 } 78 if (!TEST_int_eq(BIO_seek(in_bio, 0), 1)) 79 goto err; 80 81 len = 8; /* Do a small partial read to start with */ 82 while (!BIO_eof(in_bio)) { 83 if (!TEST_int_eq(BIO_read_ex(in_bio, buf, len, &bytes), 1)) 84 break; 85 if (!TEST_mem_eq(buf, bytes, expected + count, bytes)) 86 goto err; 87 count += bytes; 88 len = sizeof(buf); /* fill the buffer on subsequent reads */ 89 } 90 if (!TEST_int_eq(count, readbytes)) 91 goto err; 92 ret = 1; 93 err: 94 BIO_free(in); 95 BIO_free_all(in_bio); 96 BIO_free(readbuf_bio); 97 return ret; 98 } 99 100 typedef enum OPTION_choice { 101 OPT_ERR = -1, 102 OPT_EOF = 0, 103 OPT_TEST_ENUM 104 } OPTION_CHOICE; 105 106 const OPTIONS *test_get_options(void) 107 { 108 static const OPTIONS test_options[] = { 109 OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("file\n"), 110 { OPT_HELP_STR, 1, '-', "file\tFile to run tests on.\n" }, 111 { NULL } 112 }; 113 return test_options; 114 } 115 116 int setup_tests(void) 117 { 118 OPTION_CHOICE o; 119 120 while ((o = opt_next()) != OPT_EOF) { 121 switch (o) { 122 case OPT_TEST_CASES: 123 break; 124 default: 125 return 0; 126 } 127 } 128 filename = test_get_argument(0); 129 130 ADD_ALL_TESTS(test_readbuffer_file_bio, 3); 131 return 1; 132 } 133