@@ -9,24 +9,92 @@ static const struct {
9
9
const char * input ;
10
10
const char * output ;
11
11
int stream_errno ;
12
+ int eof ;
12
13
} tests [] = {
13
- { "p=C3=A4=C3=A4t=C3=B6s" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 },
14
- { "p=c3=a4=c3=a4t=c3=b6s= \n" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 },
15
- { "p=c3=a4= \t \n=c3=\r\n=a4t= \r\n=c3=b6s" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 },
16
-
17
- { "p=c3=a4\rasdf" , "p\xC3\xA4" , EINVAL },
18
- { "p=c" , "p" , EPIPE },
19
- { "p=A" , "p" , EPIPE },
20
- { "p=Ax" , "p" , EINVAL },
21
- { "p=c3=a4=c3=a4t=c3=b6s= " , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , EPIPE }
14
+ { "p=C3=A4=C3=A4t=C3=B6s" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 , 0 },
15
+ { "p=c3=a4=c3=a4t=c3=b6s= \n" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 , 0 },
16
+ { "p=c3=a4= \t \n=c3=\r\n=a4t= \r\n=c3=b6s" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 , 1 },
17
+ { "p=c3=a4= \t \n=c3=\r\n=a4t= \r\n=c3=b6s" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 , 2 },
18
+ { "p=c3=a4= \t \n=c3=\r\n=a4t= \r\n=c3=b6s" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 , 3 },
19
+ { "p=c3=a4= \t \n=c3=\r\n=a4t= \r\n=c3=b6s" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 , 4 },
20
+ { "p=c3=a4= \t \n=c3=\r\n=a4t= \r\n=c3=b6s" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 , 5 },
21
+ { "p=c3=a4= \t \n=c3=\r\n=a4t= \r\n=c3=b6s" , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , 0 , 7 },
22
+ { "p=c3" , "p\xC3" , 0 , 2 },
23
+ { "=0A=0D " , "\n\r" , 0 , 7 },
24
+ { "foo_bar" , "foo_bar" , 0 , 0 },
25
+ { "\n\n" , "\r\n\r\n" , 0 , 0 },
26
+ { "\r\n\n\n\r\n" , "\r\n\r\n\r\n\r\n" , 0 , 0 },
27
+ /* Unnecessarily encoded */
28
+ { "=66=6f=6f=42=61=72" , "fooBar" , 0 , 4 },
29
+ /* Expected to be encoded but not */
30
+ { "\xc3\x9c" "berm=c3=a4\xc3\x9figer Gebrauch" , "\xc3\x9c" "berm\xc3\xa4\xc3\x9figer Gebrauch" , 0 , 9 },
31
+ /* Decode control characters */
32
+ { "=0C=07" , "\x0C\x07" , 0 , 0 },
33
+ /* Data */
34
+ { "=DE=AD=BE=EF" , "\xDE\xAD\xBE\xEF" , 0 , 0 },
35
+ /* Non hex data */
36
+ { "=FJ=X1" , "" , EINVAL , 0 },
37
+ /* No content allowed after Soft Line Break */
38
+ { "=C3=9C = " ,"\xc3\x9c " , EPIPE , 0 },
39
+ /* Boundary delimiter */
40
+ { "=C3=9C=\r\n-------" ,"\xc3\x9c-------" , 0 , 0 },
41
+ { "=----------- =C3=9C" ,"" , EINVAL , 0 },
42
+ { "=___________ =C3=9C" ,"" , EINVAL , 0 },
43
+ { "___________ =C3=9C" ,"___________ \xc3\x9c" , 0 , 0 },
44
+ { "=2D=2D=2D=2D=2D=2D =C3=9C" ,"------ \xc3\x9c" , 0 , 0 },
45
+ { "=FC=83=BF=BF=BF=BF" , "\xFC\x83\xBF\xBF\xBF\xBF" , 0 , 0 },
46
+ { "=FE=FE=FF=FF" , "\xFE\xFE\xFF\xFF" , 0 , 0 },
47
+ { "\xFF=C3=9C\xFE\xFF" "foobar" , "\xFF\xc3\x9c\xFE\xFF" "foobar" , 0 , 0 },
48
+
49
+ { "p=c3=a4\rasdf" , "p\xC3\xA4" , EINVAL , 0 },
50
+ { "=___________ \xc3\x9c" ,"" , EINVAL , 0 },
51
+ { "p=c" , "p" , EPIPE , 0 },
52
+ { "p=A" , "p" , EPIPE , 0 },
53
+ { "p=Ax" , "p" , EINVAL , 0 },
54
+ { "___________ \xc3\x9c=C3=9" ,"___________ \xc3\x9c\xC3" , EPIPE , 0 },
55
+ { "p=c3=a4=c3=a4t=c3=b6s= " , "p\xC3\xA4\xC3\xA4t\xC3\xB6s" , EPIPE , 0 },
56
+ /* Soft Line Break example from the RFC */
57
+ {
58
+ "Now's the time =\r\nfor all folk to come=\r\n to the aid of "
59
+ "their country." , "Now's the time for all folk to come to the"
60
+ " aid of their country." , 0 , 41
61
+ },
22
62
};
23
63
64
+ static bool is_hex (char c ) {
65
+ return ((c >= 48 && c <= 57 ) || (c >= 65 && c <= 70 )
66
+ || (c >= 97 && c <= 102 ));
67
+
68
+ }
69
+
70
+ static unsigned int
71
+ get_encoding_size_diff (const char * qp_input , unsigned int limit )
72
+ {
73
+ unsigned int encoded_chars = 0 ;
74
+ unsigned int soft_line_breaks = 0 ;
75
+ for (unsigned int i = 0 ; i < limit ; i ++ ) {
76
+ char c = qp_input [i ];
77
+ if (c == '=' && i + 2 < limit ) {
78
+ if (qp_input [i + 1 ] == '\r' && qp_input [i + 2 ] == '\n' ) {
79
+ soft_line_breaks ++ ;
80
+ i += 2 ;
81
+ limit += 3 ;
82
+ } else if (is_hex (qp_input [i + 1 ]) && is_hex (qp_input [i + 2 ])) {
83
+ encoded_chars ++ ;
84
+ i += 2 ;
85
+ limit += 2 ;
86
+ }
87
+ }
88
+ }
89
+ return encoded_chars * 2 + soft_line_breaks * 3 ;
90
+ }
91
+
24
92
static void
25
93
decode_test (const char * qp_input , const char * output , int stream_errno ,
26
- unsigned int buffer_size )
94
+ unsigned int buffer_size , unsigned int eof )
27
95
{
28
96
size_t qp_input_len = strlen (qp_input );
29
- struct istream * input_data , * input ;
97
+ struct istream * input_data , * input_data_limited , * input ;
30
98
const unsigned char * data ;
31
99
size_t i , size ;
32
100
string_t * str = t_str_new (32 );
@@ -57,7 +125,49 @@ decode_test(const char *qp_input, const char *output, int stream_errno,
57
125
test_assert (ret == -1 );
58
126
test_assert (input -> stream_errno == stream_errno );
59
127
60
- test_assert (strcmp (str_c (str ), output ) == 0 );
128
+ if (stream_errno == 0 ) {
129
+ /* Test seeking on streams where the testcases do not
130
+ * expect a specific errno already */
131
+ uoff_t v_off = input -> v_offset ;
132
+ /* Seeking backwards */
133
+ i_stream_seek (input , 0 );
134
+ test_assert (input -> v_offset == 0 );
135
+
136
+ /* Seeking forward */
137
+ i_stream_seek (input , v_off + 1 );
138
+ test_assert (input -> stream_errno == ESPIPE );
139
+ }
140
+ /* Compare outputs */
141
+ test_assert_strcmp (str_c (str ), output );
142
+
143
+ if (eof > 0 ) {
144
+ /* Insert early EOF into input_data */
145
+ i_stream_seek (input_data , 0 );
146
+ str_truncate (str , 0 );
147
+ input_data_limited = i_stream_create_limit (input_data , eof );
148
+ test_istream_set_allow_eof (input_data_limited , TRUE);
149
+ i_stream_unref (& input );
150
+ input = i_stream_create_qp_decoder (input_data_limited );
151
+ while ((ret = i_stream_read_more (input , & data , & size )) > 0 ) {
152
+ str_append_data (str , data , size );
153
+ i_stream_skip (input , size );
154
+ }
155
+ test_assert (ret == -1 );
156
+ /* If there is no error still assume that the result is valid
157
+ * till artifical eof. */
158
+ if (input -> stream_errno == 0 ) {
159
+ unsigned int encoding_margin =
160
+ get_encoding_size_diff (qp_input , eof );
161
+
162
+ /* Cut the expected output at eof of input*/
163
+ const char * expected_output =
164
+ t_strdup_printf ("%.*s" , eof - encoding_margin ,
165
+ output );
166
+ test_assert_strcmp (str_c (str ), expected_output );
167
+ }
168
+ test_assert (input -> eof );
169
+ }
170
+
61
171
i_stream_unref (& input );
62
172
i_stream_unref (& input_data );
63
173
}
@@ -70,7 +180,7 @@ static void test_istream_qp_decoder(void)
70
180
test_begin (t_strdup_printf ("istream qp decoder %u" , i + 1 ));
71
181
for (j = 1 ; j < 10 ; j ++ ) T_BEGIN {
72
182
decode_test (tests [i ].input , tests [i ].output ,
73
- tests [i ].stream_errno , j );
183
+ tests [i ].stream_errno , j , tests [ i ]. eof );
74
184
} T_END ;
75
185
test_end ();
76
186
}
0 commit comments