From: Stephan Bosch Date: Sat, 30 Mar 2019 18:12:39 +0000 (+0100) Subject: lib: istream-base64-decoder - Use the new low-level incremental Base64 decoding API. X-Git-Tag: 2.3.9~277 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=69c1d5aaf0cf46d180d6f84ea289018b561cbc1f;p=thirdparty%2Fdovecot%2Fcore.git lib: istream-base64-decoder - Use the new low-level incremental Base64 decoding API. --- diff --git a/src/lib/istream-base64-decoder.c b/src/lib/istream-base64-decoder.c index aa94be5881..c6d07f24b8 100644 --- a/src/lib/istream-base64-decoder.c +++ b/src/lib/istream-base64-decoder.c @@ -10,7 +10,7 @@ struct base64_decoder_istream { struct istream_private istream; - const struct base64_scheme *b64; + struct base64_decoder decoder; }; static int i_stream_read_parent(struct istream_private *stream) @@ -49,18 +49,12 @@ i_stream_base64_try_decode_block(struct base64_decoder_istream *bstream) i_stream_try_alloc(stream, (size+3)/4*3, &avail); buffer_avail = stream->buffer_size - stream->pos; - - if ((size + 3) / 4 * 3 > buffer_avail) { - /* can't fit everything to destination buffer. - write as much as we can. */ - size = (buffer_avail / 3) * 4; - if (size == 0) - return -2; - } + if (buffer_avail == 0) + return -2; buffer_create_from_data(&buf, stream->w_buffer + stream->pos, buffer_avail); - if (base64_scheme_decode(bstream->b64, data, size, &pos, &buf) < 0) { + if (base64_decode_more(&bstream->decoder, data, size, &pos, &buf) < 0) { io_stream_set_error(&stream->iostream, "Invalid base64 data: 0x%s", binary_to_hex(data+pos, I_MIN(size-pos, 8))); @@ -74,28 +68,16 @@ i_stream_base64_try_decode_block(struct base64_decoder_istream *bstream) } static void -i_stream_base64_last_partial_block(struct base64_decoder_istream *bstream) +i_stream_base64_finish_decode(struct base64_decoder_istream *bstream) { struct istream_private *stream = &bstream->istream; - const unsigned char *data; - size_t i, size; - /* base64 input with a partial block */ - data = i_stream_get_data(stream->parent, &size); - for (i = 0; i < size; i++) { - if (!base64_scheme_is_valid_char(bstream->b64, data[i])) - break; - } - if (i == size) { + i_assert(i_stream_get_data_size(stream->parent) == 0); + + if (base64_decode_finish(&bstream->decoder) < 0) { io_stream_set_error(&stream->iostream, - "base64 input ends with a partial block: 0x%s", - binary_to_hex(data, size)); + "Base64 data ends prematurely"); stream->istream.stream_errno = EPIPE; - } else { - io_stream_set_error(&stream->iostream, - "Invalid base64 data: 0x%s", - binary_to_hex(data, size)); - stream->istream.stream_errno = EINVAL; } } @@ -106,12 +88,16 @@ static ssize_t i_stream_base64_decoder_read(struct istream_private *stream) size_t pre_count, post_count; int ret; + if (base64_decode_is_finished(&bstream->decoder)) { + stream->istream.eof = TRUE; + return -1; + } + do { ret = i_stream_read_parent(stream); if (ret <= 0) { - if (ret < 0 && stream->istream.stream_errno == 0 && - i_stream_get_data_size(stream->parent) > 0) - i_stream_base64_last_partial_block(bstream); + if (ret < 0 && stream->istream.stream_errno == 0) + i_stream_base64_finish_decode(bstream); return ret; } @@ -132,6 +118,9 @@ static void i_stream_base64_decoder_seek(struct istream_private *stream, uoff_t v_offset, bool mark) { + struct base64_decoder_istream *bstream = + (struct base64_decoder_istream *)stream; + if (v_offset < stream->istream.v_offset) { /* seeking backwards - go back to beginning and seek forward from there. */ @@ -139,6 +128,8 @@ i_stream_base64_decoder_seek(struct istream_private *stream, stream->skip = stream->pos = 0; stream->istream.v_offset = 0; i_stream_seek(stream->parent, 0); + + base64_decode_reset(&bstream->decoder); } i_stream_default_seek_nonseekable(stream, v_offset, mark); } @@ -150,7 +141,6 @@ i_stream_create_base64_decoder_common(const struct base64_scheme *b64, struct base64_decoder_istream *bstream; bstream = i_new(struct base64_decoder_istream, 1); - bstream->b64 = b64; bstream->istream.max_buffer_size = input->real_stream->max_buffer_size; bstream->istream.read = i_stream_base64_decoder_read; @@ -159,6 +149,9 @@ i_stream_create_base64_decoder_common(const struct base64_scheme *b64, bstream->istream.istream.readable_fd = FALSE; bstream->istream.istream.blocking = input->blocking; bstream->istream.istream.seekable = input->seekable; + + base64_decode_init(&bstream->decoder, b64, 0); + return i_stream_create(&bstream->istream, input, i_stream_get_fd(input), 0); } diff --git a/src/lib/test-istream-base64-decoder.c b/src/lib/test-istream-base64-decoder.c index cc642352a6..2a86aae961 100644 --- a/src/lib/test-istream-base64-decoder.c +++ b/src/lib/test-istream-base64-decoder.c @@ -25,14 +25,14 @@ static const struct base64_istream_test base64_tests[] = { { "\n", "", 0 }, { "\r\n", "", 0 }, { " ", "", 0 }, - { "foo", "", EPIPE }, - { "foo ", "", EINVAL }, + { "foo", "\x7e\x8a", EPIPE }, + { "foo ","\x7e\x8a", EPIPE }, { "Zm9vC", "foo", EPIPE }, { "Zm9v!", "foo", EINVAL }, - { "Zm9!v", "", EINVAL }, - { "Zm9 v", "", EINVAL }, - { "Zm 9v", "", EINVAL }, - { "Z m9v", "", EINVAL }, + { "Zm9!v", "fo", EINVAL }, + { "Zm9 v", "foo", 0 }, + { "Zm 9v", "foo", 0 }, + { "Z m9v", "foo", 0 }, }; static const struct base64_istream_test base64url_tests[] = { @@ -49,14 +49,14 @@ static const struct base64_istream_test base64url_tests[] = { { "\n", "", 0 }, { "\r\n", "", 0 }, { " ", "", 0 }, - { "foo", "", EPIPE }, - { "foo ", "", EINVAL }, + { "foo", "\x7e\x8a", EPIPE }, + { "foo ","\x7e\x8a", EPIPE }, { "Zm9vC", "foo", EPIPE }, { "Zm9v!", "foo", EINVAL }, - { "Zm9!v", "", EINVAL }, - { "Zm9 v", "", EINVAL }, - { "Zm 9v", "", EINVAL }, - { "Z m9v", "", EINVAL }, + { "Zm9!v", "fo", EINVAL }, + { "Zm9 v", "foo", 0 }, + { "Zm 9v", "foo", 0 }, + { "Z m9v", "foo", 0 }, }; static void