~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/lib-mail/test-istream-attachment.c

  • Committer: Package Import Robot
  • Author(s): Jaldhar H. Vyas
  • Date: 2013-09-09 00:57:32 UTC
  • mfrom: (1.13.11)
  • mto: (4.8.5 experimental) (1.16.1)
  • mto: This revision was merged to the branch mainline in revision 97.
  • Revision ID: package-import@ubuntu.com-20130909005732-dn1eell8srqbhh0e
Tags: upstream-2.2.5
ImportĀ upstreamĀ versionĀ 2.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2007-2013 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "array.h"
 
5
#include "str.h"
 
6
#include "sha1.h"
 
7
#include "hash-format.h"
 
8
#include "safe-mkstemp.h"
 
9
#include "istream.h"
 
10
#include "istream-crlf.h"
 
11
#include "istream-attachment-extractor.h"
 
12
#include "istream-attachment-connector.h"
 
13
#include "ostream.h"
 
14
#include "test-common.h"
 
15
 
 
16
#include <stdio.h>
 
17
#include <unistd.h>
 
18
 
 
19
#define BINARY_TEXT_LONG "we have\ra lot \nof \0binary stuff in here\n" \
 
20
"b adjig sadjg jasidgjiaehga3wht8a3w8ghxjc dsgad hasdghsd gasd ds" \
 
21
"jdsoga sjdga0w3tjhawjgsertniq3n5oqerjqw2r89q23h awhrqh835r8a"
 
22
#define BINARY_TEXT_LONG_BASE64 \
 
23
"d2UgaGF2ZQ1hIGxvdCAKb2YgAGJpbmFyeSBzdHVmZiBpbiBoZXJlCmIgYWRqaWcgc2FkamcgamFz\r\n" \
 
24
"aWRnamlhZWhnYTN3aHQ4YTN3OGdoeGpjIGRzZ2FkIGhhc2RnaHNkIGdhc2QgZHNqZHNvZ2Egc2pk\r\n" \
 
25
"Z2EwdzN0amhhd2pnc2VydG5pcTNuNW9xZXJqcXcycjg5cTIzaCBhd2hycWg4MzVyOGE="
 
26
 
 
27
#define BINARY_TEXT_SHORT "eh"
 
28
#define BINARY_TEXT_SHORT_BASE64 "ZWg="
 
29
 
 
30
static const char mail_input[] =
 
31
"MIME-Version: 1.0\r\n"
 
32
"Content-Type: multipart/alternative;\r\n boundary=\"bound\"\r\n"
 
33
"\r\n"
 
34
"mime header\r\n"
 
35
"\r\n--bound\r\n"
 
36
"Content-Transfer-Encoding: base64\r\n"
 
37
"Content-Type: text/plain\r\n"
 
38
"\r\n"
 
39
BINARY_TEXT_LONG_BASE64
 
40
"\r\n--bound\r\n"
 
41
"Content-Type: text/plain\r\n"
 
42
"Content-Transfer-Encoding: base64\r\n"
 
43
"\r\n"
 
44
BINARY_TEXT_SHORT_BASE64
 
45
"\r\n--bound--\r\n";
 
46
 
 
47
static const char mail_output[] =
 
48
"MIME-Version: 1.0\r\n"
 
49
"Content-Type: multipart/alternative;\r\n boundary=\"bound\"\r\n"
 
50
"\r\n"
 
51
"mime header\r\n"
 
52
"\r\n--bound\r\n"
 
53
"Content-Transfer-Encoding: base64\r\n"
 
54
"Content-Type: text/plain\r\n"
 
55
"\r\n"
 
56
"\r\n--bound\r\n"
 
57
"Content-Type: text/plain\r\n"
 
58
"Content-Transfer-Encoding: base64\r\n"
 
59
"\r\n"
 
60
"\r\n--bound--\r\n";
 
61
 
 
62
struct attachment {
 
63
        size_t buffer_offset;
 
64
        uoff_t start_offset;
 
65
        uoff_t encoded_size, decoded_size;
 
66
        unsigned int base64_blocks_per_line;
 
67
};
 
68
 
 
69
static buffer_t *attachment_data;
 
70
static ARRAY(struct attachment) attachments;
 
71
 
 
72
static int test_open_temp_fd(void *context ATTR_UNUSED)
 
73
{
 
74
        string_t *str = t_str_new(128);
 
75
        int fd;
 
76
 
 
77
        str_append(str, "/tmp/dovecot-test.");
 
78
        fd = safe_mkstemp(str, 0600, (uid_t)-1, (gid_t)-1);
 
79
        if (fd == -1)
 
80
                i_fatal("safe_mkstemp(%s) failed: %m", str_c(str));
 
81
        (void)unlink(str_c(str));
 
82
        return fd;
 
83
}
 
84
 
 
85
static int test_open_attachment_ostream(struct istream_attachment_info *info,
 
86
                                        struct ostream **output_r,
 
87
                                        void *context ATTR_UNUSED)
 
88
{
 
89
        struct attachment *a;
 
90
 
 
91
        if (attachment_data == NULL)
 
92
                attachment_data = buffer_create_dynamic(default_pool, 1024);
 
93
        if (!array_is_created(&attachments))
 
94
                i_array_init(&attachments, 8);
 
95
        a = array_append_space(&attachments);
 
96
        a->buffer_offset = attachment_data->used;
 
97
        a->start_offset = info->start_offset;
 
98
        a->encoded_size = info->encoded_size;
 
99
        a->base64_blocks_per_line = info->base64_blocks_per_line;
 
100
        test_assert(strlen(info->hash) == 160/8*2); /* sha1 size */
 
101
 
 
102
        *output_r = o_stream_create_buffer(attachment_data);
 
103
        if (o_stream_seek(*output_r, a->buffer_offset) < 0)
 
104
                i_unreached();
 
105
        return 0;
 
106
}
 
107
 
 
108
static int test_close_attachment_ostream(struct ostream *output, bool success,
 
109
                                         void *context ATTR_UNUSED)
 
110
{
 
111
        struct attachment *a;
 
112
 
 
113
        i_assert(success);
 
114
 
 
115
        a = array_idx_modifiable(&attachments, array_count(&attachments)-1);
 
116
        a->decoded_size = output->offset - a->buffer_offset;
 
117
 
 
118
        if (o_stream_nfinish(output) < 0)
 
119
                i_unreached();
 
120
        o_stream_destroy(&output);
 
121
        return 0;
 
122
}
 
123
 
 
124
static struct istream *
 
125
test_build_original_istream(struct istream *base_input, uoff_t msg_size)
 
126
{
 
127
        struct istream_attachment_connector *conn;
 
128
        const unsigned char *data = attachment_data->data;
 
129
        const struct attachment *a;
 
130
        struct istream *input;
 
131
        uoff_t data_size = attachment_data->used;
 
132
        const char *error;
 
133
 
 
134
        conn = istream_attachment_connector_begin(base_input, msg_size);
 
135
        array_foreach(&attachments, a) {
 
136
                input = i_stream_create_from_data(data, a->decoded_size);
 
137
                if (istream_attachment_connector_add(conn, input,
 
138
                                a->start_offset, a->encoded_size,
 
139
                                a->base64_blocks_per_line, TRUE, &error) < 0)
 
140
                        i_unreached();
 
141
                i_stream_unref(&input);
 
142
 
 
143
                i_assert(a->decoded_size <= data_size);
 
144
                data += a->decoded_size;
 
145
                data_size -= a->decoded_size;
 
146
        }
 
147
        i_assert(data_size == 0);
 
148
        return istream_attachment_connector_finish(&conn);
 
149
}
 
150
 
 
151
static void
 
152
get_istream_attachment_settings(struct istream_attachment_settings *set_r)
 
153
{
 
154
        const char *error;
 
155
 
 
156
        memset(set_r, 0, sizeof(*set_r));
 
157
        set_r->min_size = 1;
 
158
        set_r->drain_parent_input = TRUE;
 
159
        set_r->open_temp_fd = test_open_temp_fd;
 
160
        set_r->open_attachment_ostream = test_open_attachment_ostream;
 
161
        set_r->close_attachment_ostream= test_close_attachment_ostream;
 
162
        if (hash_format_init("%{sha1}", &set_r->hash_format, &error) < 0)
 
163
                i_unreached();
 
164
}
 
165
 
 
166
static int test_input_stream(struct istream *file_input)
 
167
{
 
168
        struct istream_attachment_settings set;
 
169
        struct istream *input, *input2;
 
170
        const unsigned char *data;
 
171
        size_t size;
 
172
        struct sha1_ctxt hash;
 
173
        uoff_t msg_size;
 
174
        buffer_t *base_buf;
 
175
        unsigned char hash_file[SHA1_RESULTLEN], hash_attached[SHA1_RESULTLEN];
 
176
        int ret = 0;
 
177
 
 
178
        /* get hash when directly reading input */
 
179
        input = i_stream_create_crlf(file_input);
 
180
        sha1_init(&hash);
 
181
        while (i_stream_read_data(input, &data, &size, 0) > 0) {
 
182
                sha1_loop(&hash, data, size);
 
183
                i_stream_skip(input, size);
 
184
        }
 
185
        sha1_result(&hash, hash_file);
 
186
        msg_size = input->v_offset;
 
187
        i_stream_unref(&input);
 
188
 
 
189
        /* read through attachment extractor */
 
190
        get_istream_attachment_settings(&set);
 
191
 
 
192
        i_stream_seek(file_input, 0);
 
193
        input = i_stream_create_crlf(file_input);
 
194
        input2 = i_stream_create_attachment_extractor(input, &set, NULL);
 
195
        i_stream_unref(&input);
 
196
        base_buf = buffer_create_dynamic(default_pool, 1024);
 
197
        while (i_stream_read_data(input2, &data, &size, 0) > 0) {
 
198
                buffer_append(base_buf, data, size);
 
199
                i_stream_skip(input2, size);
 
200
        }
 
201
        i_stream_unref(&input2);
 
202
 
 
203
        /* rebuild the original stream and see if the hash matches */
 
204
        input2 = i_stream_create_from_data(base_buf->data, base_buf->used);
 
205
        input = test_build_original_istream(input2, msg_size);
 
206
        i_stream_unref(&input2);
 
207
 
 
208
        sha1_init(&hash);
 
209
        while (i_stream_read_data(input, &data, &size, 0) > 0) {
 
210
                sha1_loop(&hash, data, size);
 
211
                i_stream_skip(input, size);
 
212
        }
 
213
        sha1_result(&hash, hash_attached);
 
214
        i_stream_unref(&input);
 
215
 
 
216
        ret = memcmp(hash_file, hash_attached, SHA1_RESULTLEN) == 0 ? 0 : -1;
 
217
 
 
218
        i_stream_unref(&file_input);
 
219
        buffer_free(&base_buf);
 
220
        if (attachment_data != NULL)
 
221
                buffer_free(&attachment_data);
 
222
        if (array_is_created(&attachments))
 
223
                array_free(&attachments);
 
224
        return ret;
 
225
}
 
226
 
 
227
static void test_istream_attachment(void)
 
228
{
 
229
        struct istream_attachment_settings set;
 
230
        struct istream *datainput, *input;
 
231
        const unsigned char *data;
 
232
        size_t i, size;
 
233
        int ret;
 
234
 
 
235
        test_begin("istream attachment");
 
236
        datainput = test_istream_create_data(mail_input, sizeof(mail_input));
 
237
        test_istream_set_allow_eof(datainput, FALSE);
 
238
 
 
239
        get_istream_attachment_settings(&set);
 
240
        input = i_stream_create_attachment_extractor(datainput, &set, NULL);
 
241
 
 
242
        for (i = 1; i <= sizeof(mail_input); i++) {
 
243
                test_istream_set_size(datainput, i);
 
244
                while ((ret = i_stream_read(input)) > 0) ;
 
245
                test_assert(ret == 0);
 
246
        }
 
247
        test_istream_set_allow_eof(datainput, TRUE);
 
248
        while ((ret = i_stream_read(input)) > 0) ;
 
249
        test_assert(ret == -1);
 
250
 
 
251
        data = i_stream_get_data(input, &size);
 
252
        test_assert(size == sizeof(mail_output) &&
 
253
                    memcmp(data, mail_output, size) == 0);
 
254
 
 
255
        data = attachment_data->data;
 
256
        test_assert(attachment_data->used ==
 
257
                    sizeof(BINARY_TEXT_LONG)-1 + strlen(BINARY_TEXT_SHORT));
 
258
        test_assert(memcmp(data, BINARY_TEXT_LONG, sizeof(BINARY_TEXT_LONG)-1) == 0);
 
259
        test_assert(memcmp(data + sizeof(BINARY_TEXT_LONG)-1,
 
260
                           BINARY_TEXT_SHORT, strlen(BINARY_TEXT_SHORT)) == 0);
 
261
        i_stream_unref(&input);
 
262
        i_stream_unref(&datainput);
 
263
        test_end();
 
264
}
 
265
 
 
266
static int test_input_file(const char *path)
 
267
{
 
268
        struct istream *file_input;
 
269
        int ret = 0;
 
270
 
 
271
        lib_init();
 
272
 
 
273
        file_input = i_stream_create_file(path, 64);
 
274
        if (test_input_stream(file_input) < 0) {
 
275
                fprintf(stderr, "istream-attachment-extractor: mismatch on file %s\n",
 
276
                        path);
 
277
                ret = -1;
 
278
        }
 
279
        i_stream_unref(&file_input);
 
280
 
 
281
        lib_deinit();
 
282
        return ret;
 
283
}
 
284
 
 
285
int main(int argc, char *argv[])
 
286
{
 
287
        static void (*test_functions[])(void) = {
 
288
                test_istream_attachment,
 
289
                NULL
 
290
        };
 
291
        if (argc > 1)
 
292
                return test_input_file(argv[1]) < 0 ? 1 : 0;
 
293
        else
 
294
                return test_run(test_functions);
 
295
}