]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: istream-base64-decoder - Use the new low-level incremental Base64 decoding API.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sat, 30 Mar 2019 18:12:39 +0000 (19:12 +0100)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 10 Sep 2019 07:02:26 +0000 (10:02 +0300)
src/lib/istream-base64-decoder.c
src/lib/test-istream-base64-decoder.c

index aa94be58818f57d5e16330d0c246861fb235ad3f..c6d07f24b8b081725a5e86491934ad6113897faa 100644 (file)
@@ -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);
 }
index cc642352a6b0f724ee90b50f6cff49d3eb52e1a6..2a86aae961793f45c2f2c2b72b1bf1aa9043376d 100644 (file)
@@ -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