numpack.c \
ostream.c \
ostream-buffer.c \
- ostream-escaped.c \
ostream-failure-at.c \
ostream-file.c \
ostream-hash.c \
nfs-workarounds.h \
numpack.h \
ostream.h \
- ostream-escaped.h \
ostream-failure-at.h \
ostream-file-private.h \
ostream-hash.h \
test-net.c \
test-numpack.c \
test-ostream-buffer.c \
- test-ostream-escaped.c \
test-ostream-failure-at.c \
test-ostream-file.c \
test-ostream-multiplex.c \
+++ /dev/null
-/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "str.h"
-#include "ostream.h"
-#include "ostream-private.h"
-#include "ostream-escaped.h"
-
-struct escaped_ostream {
- struct ostream_private ostream;
- ostream_escaped_escape_formatter_t format;
-
- string_t *buf;
- bool flushed;
-};
-
-static ssize_t
-o_stream_escaped_send_outbuf(struct escaped_ostream *estream)
-{
- ssize_t ret;
-
- if (estream->flushed)
- return 1; /* nothing to send */
- ret = o_stream_send(estream->ostream.parent, str_data(estream->buf), str_len(estream->buf));
- if (ret < 0) {
- o_stream_copy_error_from_parent(&estream->ostream);
- return -1;
- }
- if ((size_t)ret != str_len(estream->buf)) {
- /* move data */
- str_delete(estream->buf, 0, ret);
- return 0;
- }
- str_truncate(estream->buf, 0);
- estream->flushed = TRUE;
- return 1;
-}
-
-static ssize_t
-o_stream_escaped_send_chunk(struct escaped_ostream *estream,
- const unsigned char *data, size_t len)
-{
- size_t i, max_buffer_size;
- ssize_t ret;
-
- max_buffer_size = I_MIN(o_stream_get_max_buffer_size(estream->ostream.parent),
- estream->ostream.max_buffer_size);
- if (max_buffer_size > IO_BLOCK_SIZE) {
- /* avoid using up too much memory in case of large buffers */
- max_buffer_size = IO_BLOCK_SIZE;
- }
-
- for (i = 0; i < len; i++) {
- if (str_len(estream->buf) + 2 > max_buffer_size) { /* escaping takes at least two bytes */
- ret = o_stream_escaped_send_outbuf(estream);
- if (ret < 0) {
- estream->ostream.ostream.offset += i;
- return ret;
- }
- if (ret == 0)
- break;
- }
- estream->format(estream->buf, data[i]);
- estream->flushed = FALSE;
- }
- estream->ostream.ostream.offset += i;
- return i;
-}
-
-static ssize_t
-o_stream_escaped_sendv(struct ostream_private *stream,
- const struct const_iovec *iov, unsigned int iov_count)
-{
- struct escaped_ostream *estream = (struct escaped_ostream *)stream;
- unsigned int iov_cur;
- ssize_t ret, bytes = 0;
-
- for (iov_cur = 0; iov_cur < iov_count; iov_cur++) {
- ret = o_stream_escaped_send_chunk(estream,
- iov[iov_cur].iov_base, iov[iov_cur].iov_len);
- if (ret < 0)
- return ret;
- bytes += ret;
- if ((size_t)ret != iov[iov_cur].iov_len)
- break;
- }
- if (o_stream_escaped_send_outbuf(estream) < 0)
- return -1;
- return bytes;
-}
-
-static int
-o_stream_escaped_flush(struct ostream_private *stream)
-{
- struct escaped_ostream *estream = (struct escaped_ostream *)stream;
- int ret;
-
- if ((ret = o_stream_escaped_send_outbuf(estream)) <= 0)
- return ret;
- return o_stream_flush_parent(stream);
-}
-
-static void o_stream_escaped_destroy(struct iostream_private *stream)
-{
- struct escaped_ostream *estream = (struct escaped_ostream *)stream;
-
- str_free(&estream->buf);
- o_stream_unref(&estream->ostream.parent);
-}
-
-void ostream_escaped_hex_format(string_t *dest, unsigned char chr)
-{
- str_printfa(dest, "%02x", chr);
-}
-
-struct ostream *
-o_stream_create_escaped(struct ostream *output,
- ostream_escaped_escape_formatter_t format)
-{
- struct escaped_ostream *estream;
-
- estream = i_new(struct escaped_ostream, 1);
- estream->ostream.sendv = o_stream_escaped_sendv;
- estream->ostream.flush = o_stream_escaped_flush;
- estream->ostream.max_buffer_size = o_stream_get_max_buffer_size(output);
- estream->ostream.iostream.destroy = o_stream_escaped_destroy;
- estream->buf = str_new(default_pool, 512);
- estream->format = format;
- estream->flushed = FALSE;
-
- return o_stream_create(&estream->ostream, output, o_stream_get_fd(output));
-}
+++ /dev/null
-#ifndef OSTREAM_ESCAPED_H
-#define OSTREAM_ESCAPED_H
-
-/**
- * Provides escape filter for ostream
- * This is intended to be used when certain (or all)
- * characters need to be escaped before sending.
-
- * Such usecases are f.ex.
- * - JSON, ostream_escaped_json_format
- * - hex, ostream_escaped_hex_format
-
- * To implement your own filter, create function
- * that matches ostream_escaped_escape_formatter_t
- * and use it as parameter
- */
-
-typedef void (*ostream_escaped_escape_formatter_t)
- (string_t *dest, unsigned char chr);
-
-void ostream_escaped_hex_format(string_t *dest, unsigned char chr);
-
-struct ostream *
-o_stream_create_escaped(struct ostream *output,
- ostream_escaped_escape_formatter_t formatter);
-
-#endif
TEST(test_net)
TEST(test_numpack)
TEST(test_ostream_buffer)
-TEST(test_ostream_escaped)
TEST(test_ostream_failure_at)
TEST(test_ostream_file)
TEST(test_ostream_multiplex)
+++ /dev/null
-/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
-
-#include "test-lib.h"
-#include "str.h"
-#include "ostream.h"
-#include "ostream-escaped.h"
-#include "json-parser.h"
-
-static void test_ostream_escaped_json(void)
-{
- struct ostream *os_sink;
- struct ostream *os_encode;
- struct const_iovec iov[2];
- string_t *str = t_str_new(64);
-
- test_begin("test_ostream_escaped_json()");
- os_sink = o_stream_create_buffer(str);
- os_encode = o_stream_create_escaped(os_sink, ostream_escaped_json_format);
-
- /* test sending iovec */
- iov[0].iov_base = "hello";
- iov[0].iov_len = 5;
- iov[1].iov_base = ", world";
- iov[1].iov_len = 7;
- test_assert(o_stream_sendv(os_encode, iov, 2) == 12);
- test_assert(os_encode->offset == 12);
- test_assert(os_sink->offset == 12);
- test_assert(strcmp(str_c(str), "hello, world") == 0);
-
- /* reset buffer */
- str_truncate(str, 0); os_sink->offset = 0; os_encode->offset = 0;
-
- /* test shrinking ostream-escaped's max buffer size */
- o_stream_set_max_buffer_size(os_encode, 10);
- o_stream_set_max_buffer_size(os_sink, 100);
- test_assert(o_stream_send(os_encode, "\x15\x00!\x00\x15\x11" "123456", 12) == 12);
- test_assert(os_encode->offset == 12);
- test_assert(os_sink->offset == 2*6 + 1 + 3*6 + 6);
- test_assert(strcmp(str_c(str), "\\u0015\\u0000!\\u0000\\u0015\\u0011123456") == 0);
-
- /* reset buffer */
- str_truncate(str, 0); os_sink->offset = 0; os_encode->offset = 0;
-
- /* test shrinking sink's max buffer size */
- o_stream_set_max_buffer_size(os_encode, 100);
- o_stream_set_max_buffer_size(os_sink, 10);
- const char *partial_input = "\x15!\x01?#&";
- ssize_t ret = o_stream_send_str(os_encode, partial_input);
- test_assert(ret < 6);
- /* send the rest */
- o_stream_set_max_buffer_size(os_sink, 100);
- ret += o_stream_send_str(os_encode, partial_input + ret);
- test_assert(ret == (ssize_t)strlen(partial_input));
- test_assert((ssize_t)os_encode->offset == ret);
- test_assert(os_sink->offset == str_len(str));
- test_assert(strcmp(str_c(str), "\\u0015!\\u0001?#&") == 0);
-
- o_stream_unref(&os_encode);
- o_stream_unref(&os_sink);
-
- test_end();
-}
-
-static void test_ostream_escaped_hex(void)
-{
- struct ostream *os_sink;
- struct ostream *os_encode;
- string_t *str = t_str_new(64);
-
- os_sink = o_stream_create_buffer(str);
- os_encode = o_stream_create_escaped(os_sink, ostream_escaped_hex_format);
-
- test_begin("test_ostream_escaped_hex()");
- test_assert(o_stream_send_str(os_encode, "hello, world") == 12);
- test_assert(o_stream_flush(os_encode) == 1);
-
- test_assert(strcmp(str_c(str), "68656c6c6f2c20776f726c64") == 0);
-
- o_stream_unref(&os_encode);
- o_stream_unref(&os_sink);
-
- test_end();
-}
-
-void test_ostream_escaped(void) {
- test_ostream_escaped_json();
- test_ostream_escaped_hex();
-}