src/server/test/io.c

changeset 633
392ec9026b07
parent 550
77241b3ba544
equal deleted inserted replaced
632:1defab20b477 633:392ec9026b07
29 #include "io.h" 29 #include "io.h"
30 30
31 #include "testutils.h" 31 #include "testutils.h"
32 32
33 33
34 UCX_TEST(test_io_http_stream_parse_chunk_header_hdronly_first) { 34 CX_TEST(test_io_http_stream_parse_chunk_header_hdronly_first) {
35 char *str = strdup("100\r\n"); 35 char *str = strdup("100\r\n");
36 size_t len = strlen(str); 36 size_t len = strlen(str);
37 char *str2 = strdup("12345\r\n"); 37 char *str2 = strdup("12345\r\n");
38 size_t len2 = strlen(str2); 38 size_t len2 = strlen(str2);
39 char *str3 = strdup("FF\r\n"); 39 char *str3 = strdup("FF\r\n");
40 size_t len3 = strlen(str3); 40 size_t len3 = strlen(str3);
41 41
42 UCX_TEST_BEGIN; 42 CX_TEST_DO {
43 43
44 int64_t chunklen; 44 int64_t chunklen;
45 int ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen); 45 int ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen);
46 UCX_TEST_ASSERT(ret == 5, "ret != 5"); 46 CX_TEST_ASSERT(ret == 5);
47 UCX_TEST_ASSERT(chunklen == 0x100, "wrong chunk length"); 47 CX_TEST_ASSERT(chunklen == 0x100);
48 48
49 // test 2 49 // test 2
50 ret = http_stream_parse_chunk_header(str2, len2, TRUE, &chunklen); 50 ret = http_stream_parse_chunk_header(str2, len2, TRUE, &chunklen);
51 UCX_TEST_ASSERT(ret == 7, "ret != 7 (test 2)"); 51 CX_TEST_ASSERT(ret == 7);
52 UCX_TEST_ASSERT(chunklen == 0x12345, "wrong chunk length (test 2)"); 52 CX_TEST_ASSERT(chunklen == 0x12345);
53 53
54 // test 3: hex test 54 // test 3: hex test
55 ret = http_stream_parse_chunk_header(str3, len3, TRUE, &chunklen); 55 ret = http_stream_parse_chunk_header(str3, len3, TRUE, &chunklen);
56 UCX_TEST_ASSERT(ret == 4, "ret != 7 (test 3)"); 56 CX_TEST_ASSERT(ret == 4);
57 UCX_TEST_ASSERT(chunklen == 0xFF, "wrong chunk length (test 3)"); 57 CX_TEST_ASSERT(chunklen == 0xFF);
58 58
59 UCX_TEST_END; 59 }
60 free(str); 60 free(str);
61 free(str2); 61 free(str2);
62 } 62 }
63 63
64 UCX_TEST(test_io_http_stream_parse_chunk_header_hdronly) { 64 CX_TEST(test_io_http_stream_parse_chunk_header_hdronly) {
65 char *str = strdup("\r\n100\r\n"); 65 char *str = strdup("\r\n100\r\n");
66 size_t len = strlen(str); 66 size_t len = strlen(str);
67 char *str2 = strdup("\nab\n"); 67 char *str2 = strdup("\nab\n");
68 size_t len2 = strlen(str2); 68 size_t len2 = strlen(str2);
69 69
70 UCX_TEST_BEGIN; 70 CX_TEST_DO {
71 71
72 int64_t chunklen; 72 int64_t chunklen;
73 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen); 73 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen);
74 UCX_TEST_ASSERT(ret == 7, "ret != 7"); 74 CX_TEST_ASSERT(ret == 7);
75 UCX_TEST_ASSERT(chunklen == 0x100, "wrong chunk length"); 75 CX_TEST_ASSERT(chunklen == 0x100);
76 76
77 // test 2 with just \n as line break 77 // test 2 with just \n as line break
78 ret = http_stream_parse_chunk_header(str2, len2, FALSE, &chunklen); 78 ret = http_stream_parse_chunk_header(str2, len2, FALSE, &chunklen);
79 UCX_TEST_ASSERT(ret == 4, "ret != 5 (test 2)"); 79 CX_TEST_ASSERT(ret == 4);
80 UCX_TEST_ASSERT(chunklen == 0xab, "wrong chunk length (test 2)"); 80 CX_TEST_ASSERT(chunklen == 0xab);
81 81
82 UCX_TEST_END; 82 }
83 free(str); 83 free(str);
84 free(str2); 84 free(str2);
85 } 85 }
86 86
87 UCX_TEST(test_io_http_stream_parse_chunk_header_hdronly_seq_fail) { 87 CX_TEST(test_io_http_stream_parse_chunk_header_hdronly_seq_fail) {
88 // test: after the first chunk header, \r\n is required before any new header 88 // test: after the first chunk header, \r\n is required before any new header
89 char *str = strdup("ff\r\n"); 89 char *str = strdup("ff\r\n");
90 size_t len = strlen(str); 90 size_t len = strlen(str);
91 91
92 UCX_TEST_BEGIN; 92 CX_TEST_DO {
93 93
94 int64_t chunklen; 94 int64_t chunklen;
95 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen); 95 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen);
96 UCX_TEST_ASSERT(ret == -1, "ret != -1"); 96 CX_TEST_ASSERT(ret == -1);
97 97
98 UCX_TEST_END; 98 }
99 free(str); 99 free(str);
100 } 100 }
101 101
102 UCX_TEST(test_io_http_stream_parse_chunk_header_hdr_data) { 102 CX_TEST(test_io_http_stream_parse_chunk_header_hdr_data) {
103 char *str = strdup("\r\nb\r\nhello world\r\n"); 103 char *str = strdup("\r\nb\r\nhello world\r\n");
104 size_t len = strlen(str); 104 size_t len = strlen(str);
105 105
106 UCX_TEST_BEGIN; 106 CX_TEST_DO {
107 107
108 int64_t chunklen; 108 int64_t chunklen;
109 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen); 109 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen);
110 UCX_TEST_ASSERT(ret == 5, "ret != 5"); 110 CX_TEST_ASSERT(ret == 5);
111 111
112 UCX_TEST_END; 112 }
113 free(str); 113 free(str);
114 } 114 }
115 115
116 UCX_TEST(test_io_http_stream_parse_chunk_header_empty) { 116 CX_TEST(test_io_http_stream_parse_chunk_header_empty) {
117 char *str = ""; 117 char *str = "";
118 size_t len = strlen(str); 118 size_t len = strlen(str);
119 119
120 UCX_TEST_BEGIN; 120 CX_TEST_DO {
121 121
122 int64_t chunklen; 122 int64_t chunklen;
123 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen); 123 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen);
124 UCX_TEST_ASSERT(ret == 0, "ret != 0"); 124 CX_TEST_ASSERT(ret == 0);
125 125
126 ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen); 126 ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen);
127 UCX_TEST_ASSERT(ret == 0, "ret != 0 (test 2)"); 127 CX_TEST_ASSERT(ret == 0);
128 128
129 UCX_TEST_END; 129 }
130 } 130 }
131 131
132 UCX_TEST(test_io_http_stream_parse_chunk_header_partial_first) { 132 CX_TEST(test_io_http_stream_parse_chunk_header_partial_first) {
133 char *str = strdup("123"); 133 char *str = strdup("123");
134 size_t len = strlen(str); 134 size_t len = strlen(str);
135 135
136 UCX_TEST_BEGIN; 136 CX_TEST_DO {
137 137
138 int64_t chunklen; 138 int64_t chunklen;
139 int ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen); 139 int ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen);
140 UCX_TEST_ASSERT(ret == 0, "ret != 0"); 140 CX_TEST_ASSERT(ret == 0);
141 141
142 UCX_TEST_END; 142 }
143 free(str); 143 free(str);
144 } 144 }
145 145
146 UCX_TEST(test_io_http_stream_parse_chunk_header_partial) { 146 CX_TEST(test_io_http_stream_parse_chunk_header_partial) {
147 char *str = strdup("123"); 147 char *str = strdup("123");
148 size_t len = strlen(str); 148 size_t len = strlen(str);
149 char *str2 = strdup("\r\n"); 149 char *str2 = strdup("\r\n");
150 size_t len2 = strlen(str2); 150 size_t len2 = strlen(str2);
151 char *str3 = strdup("\r"); 151 char *str3 = strdup("\r");
152 size_t len3 = strlen(str3); 152 size_t len3 = strlen(str3);
153 char *str4 = strdup("\r\n123"); 153 char *str4 = strdup("\r\n123");
154 size_t len4 = strlen(str4); 154 size_t len4 = strlen(str4);
155 155
156 UCX_TEST_BEGIN; 156 CX_TEST_DO {
157 157
158 int64_t chunklen; 158 int64_t chunklen;
159 int ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen); 159 int ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen);
160 UCX_TEST_ASSERT(ret == 0, "ret != 0"); 160 CX_TEST_ASSERT(ret == 0);
161 ret = http_stream_parse_chunk_header(str2, len2, FALSE, &chunklen); 161 ret = http_stream_parse_chunk_header(str2, len2, FALSE, &chunklen);
162 UCX_TEST_ASSERT(ret == 0, "ret != 0"); 162 CX_TEST_ASSERT(ret == 0);
163 ret = http_stream_parse_chunk_header(str3, len3, FALSE, &chunklen); 163 ret = http_stream_parse_chunk_header(str3, len3, FALSE, &chunklen);
164 UCX_TEST_ASSERT(ret == 0, "ret != 0"); 164 CX_TEST_ASSERT(ret == 0);
165 ret = http_stream_parse_chunk_header(str4, len4, FALSE, &chunklen); 165 ret = http_stream_parse_chunk_header(str4, len4, FALSE, &chunklen);
166 UCX_TEST_ASSERT(ret == 0, "ret != 0"); 166 CX_TEST_ASSERT(ret == 0);
167 167
168 UCX_TEST_END; 168 }
169 free(str); 169 free(str);
170 free(str2); 170 free(str2);
171 free(str3); 171 free(str3);
172 free(str4); 172 free(str4);
173 } 173 }
174 174
175 UCX_TEST(test_io_http_stream_parse_chunk_header_invalid) { 175 CX_TEST(test_io_http_stream_parse_chunk_header_invalid) {
176 char *str = strdup("hello\r\n"); 176 char *str = strdup("hello\r\n");
177 size_t len = strlen(str); 177 size_t len = strlen(str);
178 char *str2 = strdup("x4\r\n\r\n123\r\n"); 178 char *str2 = strdup("x4\r\n\r\n123\r\n");
179 size_t len2 = strlen(str2); 179 size_t len2 = strlen(str2);
180 char *str3 = strdup("\r\n\r\n123\r\n"); 180 char *str3 = strdup("\r\n\r\n123\r\n");
184 char *str5 = strdup("\r\n\r\n1 2 3\r\n"); 184 char *str5 = strdup("\r\n\r\n1 2 3\r\n");
185 size_t len5 = strlen(str3); 185 size_t len5 = strlen(str3);
186 char *str6 = strdup("\r\n\r\n1 23\r\n"); 186 char *str6 = strdup("\r\n\r\n1 23\r\n");
187 size_t len6 = strlen(str3); 187 size_t len6 = strlen(str3);
188 188
189 UCX_TEST_BEGIN; 189 CX_TEST_DO {
190 190 int64_t chunklen;
191 int64_t chunklen; 191 int ret;
192 int ret; 192
193 193 ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen);
194 ret = http_stream_parse_chunk_header(str, len, TRUE, &chunklen); 194 CX_TEST_ASSERT(ret == -1);
195 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 1a)"); 195 ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen);
196 ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen); 196 CX_TEST_ASSERT(ret == -1);
197 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 1b)"); 197
198 198 ret = http_stream_parse_chunk_header(str2, len2, TRUE, &chunklen);
199 ret = http_stream_parse_chunk_header(str2, len2, TRUE, &chunklen); 199 CX_TEST_ASSERT(ret == -1);
200 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 2a)"); 200 ret = http_stream_parse_chunk_header(str2, len2, FALSE, &chunklen);
201 ret = http_stream_parse_chunk_header(str2, len2, FALSE, &chunklen); 201 CX_TEST_ASSERT(ret == -1);
202 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 2b)"); 202
203 203 ret = http_stream_parse_chunk_header(str3, len3, TRUE, &chunklen);
204 ret = http_stream_parse_chunk_header(str3, len3, TRUE, &chunklen); 204 CX_TEST_ASSERT(ret == -1);
205 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 3a)"); 205 ret = http_stream_parse_chunk_header(str3, len3, FALSE, &chunklen);
206 ret = http_stream_parse_chunk_header(str3, len3, FALSE, &chunklen); 206 CX_TEST_ASSERT(ret == -1);
207 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 3b)"); 207
208 208 ret = http_stream_parse_chunk_header(str4, len4, TRUE, &chunklen);
209 ret = http_stream_parse_chunk_header(str4, len4, TRUE, &chunklen); 209 CX_TEST_ASSERT(ret == -1);
210 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 4a)"); 210 ret = http_stream_parse_chunk_header(str4, len4, FALSE, &chunklen);
211 ret = http_stream_parse_chunk_header(str4, len4, FALSE, &chunklen); 211 CX_TEST_ASSERT(ret == -1);
212 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 4b)"); 212
213 213 ret = http_stream_parse_chunk_header(str5, len5, TRUE, &chunklen);
214 ret = http_stream_parse_chunk_header(str5, len5, TRUE, &chunklen); 214 CX_TEST_ASSERT(ret == -1);
215 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 5a)"); 215 ret = http_stream_parse_chunk_header(str5, len5, FALSE, &chunklen);
216 ret = http_stream_parse_chunk_header(str5, len5, FALSE, &chunklen); 216 CX_TEST_ASSERT(ret == -1);
217 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 5b)"); 217
218 218 ret = http_stream_parse_chunk_header(str6, len6, TRUE, &chunklen);
219 ret = http_stream_parse_chunk_header(str6, len6, TRUE, &chunklen); 219 CX_TEST_ASSERT(ret == -1);
220 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 6a)"); 220 ret = http_stream_parse_chunk_header(str6, len6, FALSE, &chunklen);
221 ret = http_stream_parse_chunk_header(str6, len6, FALSE, &chunklen); 221 CX_TEST_ASSERT(ret == -1);
222 UCX_TEST_ASSERT(ret == -1, "ret != -1 (test 6b)"); 222 }
223 223
224 UCX_TEST_END;
225 free(str); 224 free(str);
226 free(str2); 225 free(str2);
227 free(str3); 226 free(str3);
228 free(str4); 227 free(str4);
229 free(str5); 228 free(str5);
230 free(str6); 229 free(str6);
231 } 230 }
232 231
233 UCX_TEST(test_io_http_stream_parse_chunk_header_zero) { 232 CX_TEST(test_io_http_stream_parse_chunk_header_zero) {
234 char *str = strdup("\r\n0\r\n\r\n"); 233 char *str = strdup("\r\n0\r\n\r\n");
235 size_t len = strlen(str); 234 size_t len = strlen(str);
236 char *str2 = strdup("0\r\n\r\n"); 235 char *str2 = strdup("0\r\n\r\n");
237 size_t len2 = strlen(str2); 236 size_t len2 = strlen(str2);
238 237
241 size_t len3 = strlen(str3); 240 size_t len3 = strlen(str3);
242 char *str4 = strdup("\r\n0"); 241 char *str4 = strdup("\r\n0");
243 size_t len4 = strlen(str4); 242 size_t len4 = strlen(str4);
244 243
245 244
246 UCX_TEST_BEGIN; 245 CX_TEST_DO {
247 246
248 int64_t chunklen = -1; 247 int64_t chunklen = -1;
249 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen); 248 int ret = http_stream_parse_chunk_header(str, len, FALSE, &chunklen);
250 UCX_TEST_ASSERT(ret == 7, "ret != 7"); 249 CX_TEST_ASSERT(ret == 7);
251 UCX_TEST_ASSERT(chunklen == 0, "chunklen != 0"); 250 CX_TEST_ASSERT(chunklen == 0);
252 251
253 chunklen = -1; 252 chunklen = -1;
254 ret = http_stream_parse_chunk_header(str2, len2, TRUE, &chunklen); 253 ret = http_stream_parse_chunk_header(str2, len2, TRUE, &chunklen);
255 UCX_TEST_ASSERT(ret == 5, "ret != 5 (test 2)"); 254 CX_TEST_ASSERT(ret == 5);
256 UCX_TEST_ASSERT(chunklen == 0, "chunklen != 0 (test 2)"); 255 CX_TEST_ASSERT(chunklen == 0);
257 256
258 // expect 0 (incomplete) 257 // expect 0 (incomplete)
259 ret = http_stream_parse_chunk_header(str3, len3, FALSE, &chunklen); 258 ret = http_stream_parse_chunk_header(str3, len3, FALSE, &chunklen);
260 UCX_TEST_ASSERT(ret == 0, "ret != 3 (test 3)"); 259 CX_TEST_ASSERT(ret == 0);
261 260
262 ret = http_stream_parse_chunk_header(str4, len4, FALSE, &chunklen); 261 ret = http_stream_parse_chunk_header(str4, len4, FALSE, &chunklen);
263 UCX_TEST_ASSERT(ret == 0, "ret != 3 (test 4)"); 262 CX_TEST_ASSERT(ret == 0);
264 263
265 UCX_TEST_END; 264 }
266 free(str); 265 free(str);
267 free(str2); 266 free(str2);
268 free(str3); 267 free(str3);
269 free(str4); 268 free(str4);
270 } 269 }
271 270
272 271
273 UCX_TEST(test_io_httpstream_write) { 272 CX_TEST(test_io_httpstream_write) {
274 Session *sn = testutil_session(); 273 Session *sn = testutil_session();
275 274
276 TestIOStream *st = testutil_iostream(2048, TRUE); 275 TestIOStream *st = testutil_iostream(2048, TRUE);
277 IOStream *http = httpstream_new(sn->pool, (IOStream*)st); 276 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
278 277
279 UCX_TEST_BEGIN; 278 CX_TEST_DO {
279
280 char *msg = "hello world!";
281 size_t msglen = strlen(msg);
282
283 ssize_t w = net_write(http, msg, msglen);
284
285 CX_TEST_ASSERT(w == msglen);
286 CX_TEST_ASSERT(st->buf->size == msglen);
287 CX_TEST_ASSERT(!memcmp(st->buf->space, msg, msglen));
288
289 // test again, make sure the second message is written directly after the wirst one
290 char *msg2 = "test";
291 size_t msglen2 = strlen(msg2);
292
293 w = net_write(http, msg2, msglen2);
294
295 CX_TEST_ASSERT(w == msglen2);
296 CX_TEST_ASSERT(st->buf->size == msglen+msglen2);
297 CX_TEST_ASSERT(!memcmp(st->buf->space + msglen, msg2, msglen2));
298
299 }
300
301 testutil_destroy_session(sn);
302 }
303
304 CX_TEST(test_io_httpstream_chunked_write) {
305 Session *sn = testutil_session();
306
307 TestIOStream *st = testutil_iostream(2048, TRUE);
308 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
309 httpstream_enable_chunked_write(http);
310
311 CX_TEST_DO {
312
313 char *msg = "hello world!";
314 size_t msglen = strlen(msg);
315
316 char *bufmsg = "c\r\nhello world!\r\n";
317 size_t bufmsglen = strlen(bufmsg);
318
319 ssize_t w = net_write(http, msg, msglen);
320
321 cxstring s1 = cx_strn(st->buf->space, st->buf->size);
322 cxstring s2 = cx_strn(bufmsg, bufmsglen);
323
324 CX_TEST_ASSERT(w == msglen);
325 CX_TEST_ASSERT(st->buf->size == bufmsglen);
326 CX_TEST_ASSERT(!cx_strcasecmp(s1, s2));
327
328 // write again
329 w = net_write(http, msg, msglen);
330 CX_TEST_ASSERT(w == msglen);
331 CX_TEST_ASSERT(st->buf->size == 2*bufmsglen);
332
333 cxstring s3 = cx_strn(st->buf->space+bufmsglen, bufmsglen);
334 CX_TEST_ASSERT(!cx_strcasecmp(s2, s3));
335
336 }
337 }
338
339 CX_TEST(test_io_httpstream_chunked_write_end) {
340 Session *sn = testutil_session();
341
342 TestIOStream *st = testutil_iostream(2048, TRUE);
343 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
344 httpstream_enable_chunked_write(http);
345
346 CX_TEST_DO {
347
348 char *msg = "hello world!";
349 size_t msglen = strlen(msg);
350
351 char *bufmsg = "c\r\nhello world!\r\n0\r\n\r\n";
352 size_t bufmsglen = strlen(bufmsg);
353
354 ssize_t w = net_write(http, msg, msglen);
355 net_finish(http);
356
357 cxstring s1 = cx_strn(st->buf->space, st->buf->size);
358 cxstring s2 = cx_strn(bufmsg, bufmsglen);
359
360 CX_TEST_ASSERT(w == msglen);
361 CX_TEST_ASSERT(st->buf->size == bufmsglen);
362 CX_TEST_ASSERT(!cx_strcasecmp(s1, s2));
363
364 }
365 }
366
367 CX_TEST(test_io_httpstream_chunked_write_xx) {
368 // This test creates a giant buffer and writes it with
369 // chunked transfer encoding to the http stream with varying chunk length
370
371 Session *sn = testutil_session();
372
373 TestIOStream *st = testutil_iostream(2048, TRUE);
374 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
375 httpstream_enable_chunked_write(http);
376
377 CX_TEST_DO {
378
379 // create test data
380 CxBuffer *testdata = cxBufferCreate(NULL, 1024*1024*4, cxDefaultAllocator, 0);
381 for(size_t i=0;i<testdata->capacity;i++) {
382 cxBufferPut(testdata, 35+(i%91));
383 }
384
385 // write chunks, start with single diget chunk length and increase
386 // chunk size with each step
387 size_t pos = 0;
388 int j = 0;
389 ssize_t i=15;
390 while(pos<testdata->size) {
391 char *buf = testdata->space + pos;
392 size_t remaining = testdata->size - pos;
393 ssize_t len = pos + i < remaining ? i : remaining;
394 pos += len;
395
396 ssize_t w = net_write(http, buf, len);
397
398 CX_TEST_ASSERT(w == len);
399 i+=100; // increase chunk size
400 j++; // debug
401 }
402
403 // terminate chunk
404 net_finish(http);
405
406 // code below also used in test_io_httpstream_chunked_write_xx_limit
407
408 // make sure the output is correctly encoded
409 // extract chunks from st->buf by using http_stream_parse_chunk_header
410 // (which should be well-tested)
411 WSBool first_chunk = TRUE;
412 int64_t chunklen = 0;
413
414 char *buf = st->buf->space;
415 size_t bufsize = st->buf->size;
416
417 pos = 0; // st->buf position
418 size_t srcpos = 0; // testdata position
419 int debug_counter = 0;
420 while(pos < bufsize) {
421 ssize_t remaining = bufsize - pos;
422 ssize_t src_remaining = testdata->size - srcpos;
423
424 int ret = http_stream_parse_chunk_header(buf+pos, remaining, first_chunk, &chunklen);
425 first_chunk = FALSE;
426
427 // ret must always be > 0 (0: incomplete chunk header, -1: invalid syntax)
428 CX_TEST_ASSERT(ret > 0);
429 if(chunklen == 0) {
430 CX_TEST_ASSERT(src_remaining == 0);
431 break;
432 }
433
434 CX_TEST_ASSERT(chunklen <= src_remaining);
435
436 char *src_chunk = testdata->space+srcpos;
437 char *buf_chunk = buf+pos+ret;
438
439 CX_TEST_ASSERT(!memcmp(buf_chunk, src_chunk, chunklen));
440
441 pos += ret + chunklen;
442 srcpos += chunklen;
443
444 debug_counter++;
445 }
446
447 cxBufferFree(testdata);
448 testutil_destroy_session(sn);
449 testutil_iostream_destroy(st);
450
451 }
452 }
453
454 CX_TEST(test_io_httpstream_chunked_write_partial_header) {
455 Session *sn = testutil_session();
456
457 TestIOStream *st = testutil_iostream(2048, TRUE);
458 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
459 httpstream_enable_chunked_write(http);
460
461 CX_TEST_DO {
462
463 memset(st->buf->space, 0, st->buf->capacity);
280 464
281 char *msg = "hello world!"; 465 char *msg = "hello world!";
282 size_t msglen = strlen(msg); 466 size_t msglen = strlen(msg);
283 467
468 st->max_write = 1; // limit the test stream max write size
469 io_set_max_writes(1);
470
471 // only 1 byte of the header is written, 0 bytes of msg
284 ssize_t w = net_write(http, msg, msglen); 472 ssize_t w = net_write(http, msg, msglen);
285 473 CX_TEST_ASSERT(w == 0);
286 UCX_TEST_ASSERT(w == msglen, "wrong size returned by net_write"); 474 CX_TEST_ASSERT(st->buf->size == 1);
287 UCX_TEST_ASSERT(st->buf->size == msglen, "wrong buffer size"); 475 CX_TEST_ASSERT(tolower(st->buf->space[0]) == 'c');
288 UCX_TEST_ASSERT(!memcmp(st->buf->space, msg, msglen), "wrong buffer content"); 476
289 477 // next header byte: '\r'
290 // test again, make sure the second message is written directly after the wirst one
291 char *msg2 = "test";
292 size_t msglen2 = strlen(msg2);
293
294 w = net_write(http, msg2, msglen2);
295
296 UCX_TEST_ASSERT(w == msglen2, "wrong size returned by net_write (2)");
297 UCX_TEST_ASSERT(st->buf->size == msglen+msglen2, "wrong buffer size (2)");
298 UCX_TEST_ASSERT(!memcmp(st->buf->space + msglen, msg2, msglen2), "wrong buffer content (2)");
299
300 UCX_TEST_END;
301
302 testutil_destroy_session(sn);
303 }
304
305 UCX_TEST(test_io_httpstream_chunked_write) {
306 Session *sn = testutil_session();
307
308 TestIOStream *st = testutil_iostream(2048, TRUE);
309 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
310 httpstream_enable_chunked_write(http);
311
312 UCX_TEST_BEGIN;
313
314 char *msg = "hello world!";
315 size_t msglen = strlen(msg);
316
317 char *bufmsg = "c\r\nhello world!\r\n";
318 size_t bufmsglen = strlen(bufmsg);
319
320 ssize_t w = net_write(http, msg, msglen);
321
322 cxstring s1 = cx_strn(st->buf->space, st->buf->size);
323 cxstring s2 = cx_strn(bufmsg, bufmsglen);
324
325 UCX_TEST_ASSERT(w == msglen, "wrong size returned by net_write");
326 UCX_TEST_ASSERT(st->buf->size == bufmsglen, "wrong buffer size");
327 UCX_TEST_ASSERT(!cx_strcasecmp(s1, s2), "wrong buffer content");
328
329 // write again
330 w = net_write(http, msg, msglen); 478 w = net_write(http, msg, msglen);
331 UCX_TEST_ASSERT(w == msglen, "write 2: wrong return value"); 479 CX_TEST_ASSERT(w == 0);
332 UCX_TEST_ASSERT(st->buf->size == 2*bufmsglen, "write 2: wrong buf size"); 480 CX_TEST_ASSERT(st->buf->size == 2);
333 481 CX_TEST_ASSERT(st->buf->space[1] == '\r');
334 cxstring s3 = cx_strn(st->buf->space+bufmsglen, bufmsglen); 482
335 UCX_TEST_ASSERT(!cx_strcasecmp(s2, s3), "write 2: wrong buf content"); 483 // next header byte: '\n'
336 484 w = net_write(http, msg, msglen);
337 485 CX_TEST_ASSERT(w == 0);
338 UCX_TEST_END; 486 CX_TEST_ASSERT(st->buf->size == 3);
339 } 487 CX_TEST_ASSERT(st->buf->space[2] == '\n');
340 488
341 UCX_TEST(test_io_httpstream_chunked_write_end) { 489 // next: content
342 Session *sn = testutil_session(); 490 w = net_write(http, msg, msglen);
343 491 CX_TEST_ASSERT(w == 1);
344 TestIOStream *st = testutil_iostream(2048, TRUE); 492 CX_TEST_ASSERT(st->buf->size == 4);
345 IOStream *http = httpstream_new(sn->pool, (IOStream*)st); 493 CX_TEST_ASSERT(st->buf->space[3] == msg[0]);
346 httpstream_enable_chunked_write(http); 494
347
348 UCX_TEST_BEGIN;
349
350 char *msg = "hello world!";
351 size_t msglen = strlen(msg);
352
353 char *bufmsg = "c\r\nhello world!\r\n0\r\n\r\n";
354 size_t bufmsglen = strlen(bufmsg);
355
356 ssize_t w = net_write(http, msg, msglen);
357 net_finish(http);
358
359 cxstring s1 = cx_strn(st->buf->space, st->buf->size);
360 cxstring s2 = cx_strn(bufmsg, bufmsglen);
361
362 UCX_TEST_ASSERT(w == msglen, "wrong size returned by net_write");
363 UCX_TEST_ASSERT(st->buf->size == bufmsglen, "wrong buffer size");
364 UCX_TEST_ASSERT(!cx_strcasecmp(s1, s2), "wrong buffer content");
365
366
367 UCX_TEST_END;
368 }
369
370 UCX_TEST(test_io_httpstream_chunked_write_xx) {
371 // This test creates a giant buffer and writes it with
372 // chunked transfer encoding to the http stream with varying chunk length
373
374 Session *sn = testutil_session();
375
376 TestIOStream *st = testutil_iostream(2048, TRUE);
377 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
378 httpstream_enable_chunked_write(http);
379
380 UCX_TEST_BEGIN;
381
382 // create test data
383 CxBuffer *testdata = cxBufferCreate(NULL, 1024*1024*4, cxDefaultAllocator, 0);
384 for(size_t i=0;i<testdata->capacity;i++) {
385 cxBufferPut(testdata, 35+(i%91));
386 }
387
388 // write chunks, start with single diget chunk length and increase
389 // chunk size with each step
390 size_t pos = 0;
391 int j = 0;
392 ssize_t i=15;
393 while(pos<testdata->size) {
394 char *buf = testdata->space + pos;
395 size_t remaining = testdata->size - pos;
396 ssize_t len = pos + i < remaining ? i : remaining;
397 pos += len;
398
399 ssize_t w = net_write(http, buf, len);
400
401 UCX_TEST_ASSERT(w == len, "wrong size returned by net_write");
402 i+=100; // increase chunk size
403 j++; // debug
404 }
405
406 // terminate chunk
407 net_finish(http);
408
409 // code below also used in test_io_httpstream_chunked_write_xx_limit
410
411 // make sure the output is correctly encoded
412 // extract chunks from st->buf by using http_stream_parse_chunk_header
413 // (which should be well-tested)
414 WSBool first_chunk = TRUE;
415 int64_t chunklen = 0;
416
417 char *buf = st->buf->space;
418 size_t bufsize = st->buf->size;
419
420 pos = 0; // st->buf position
421 size_t srcpos = 0; // testdata position
422 int debug_counter = 0;
423 while(pos < bufsize) {
424 ssize_t remaining = bufsize - pos;
425 ssize_t src_remaining = testdata->size - srcpos;
426
427 int ret = http_stream_parse_chunk_header(buf+pos, remaining, first_chunk, &chunklen);
428 first_chunk = FALSE;
429
430 // ret must always be > 0 (0: incomplete chunk header, -1: invalid syntax)
431 UCX_TEST_ASSERT(ret > 0, "http_stream_parse_chunk_header ret <= 0");
432 if(chunklen == 0) {
433 UCX_TEST_ASSERT(src_remaining == 0, "stream end reached but src_remaining > 0");
434 break;
435 }
436
437 UCX_TEST_ASSERT(chunklen <= src_remaining, "chunklen > src_remaining");
438
439 char *src_chunk = testdata->space+srcpos;
440 char *buf_chunk = buf+pos+ret;
441
442 UCX_TEST_ASSERT(!memcmp(buf_chunk, src_chunk, chunklen), "memcmp failed");
443
444 pos += ret + chunklen;
445 srcpos += chunklen;
446
447 debug_counter++;
448 }
449
450 cxBufferFree(testdata);
451 testutil_destroy_session(sn); 495 testutil_destroy_session(sn);
452 testutil_iostream_destroy(st); 496 testutil_iostream_destroy(st);
453 497
454 UCX_TEST_END; 498 }
455 } 499 }
456 500
457 UCX_TEST(test_io_httpstream_chunked_write_partial_header) { 501 CX_TEST(test_io_httpstream_chunked_write_partial_data) {
458 Session *sn = testutil_session(); 502 Session *sn = testutil_session();
459 503
460 TestIOStream *st = testutil_iostream(2048, TRUE); 504 TestIOStream *st = testutil_iostream(2048, TRUE);
461 IOStream *http = httpstream_new(sn->pool, (IOStream*)st); 505 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
462 httpstream_enable_chunked_write(http); 506 httpstream_enable_chunked_write(http);
463 507
464 UCX_TEST_BEGIN; 508 CX_TEST_DO {
465 509
466 memset(st->buf->space, 0, st->buf->capacity); 510 memset(st->buf->space, 0, st->buf->capacity);
467 511
468 char *msg = "hello world!"; 512 char *msg = "hello world!";
469 size_t msglen = strlen(msg); 513 size_t msglen = strlen(msg);
470 514 size_t msglen_orig = msglen;
471 st->max_write = 1; // limit the test stream max write size 515
472 io_set_max_writes(1); 516 // limit first write to 3 to only write the header
473 517 st->max_write = 3;
474 // only 1 byte of the header is written, 0 bytes of msg 518 io_set_max_writes(1);
475 ssize_t w = net_write(http, msg, msglen); 519
476 UCX_TEST_ASSERT(w == 0, "write 1: wrong return value"); 520 ssize_t w = net_write(http, msg, msglen);
477 UCX_TEST_ASSERT(st->buf->size == 1, "write 1: wrong buf size"); 521
478 UCX_TEST_ASSERT(tolower(st->buf->space[0]) == 'c', "write 1: wrong buf content"); 522 CX_TEST_ASSERT(w == 0);
479 523 CX_TEST_ASSERT(st->buf->size == 3);
480 // next header byte: '\r' 524 CX_TEST_ASSERT(st->buf->space[0] == 'c');
481 w = net_write(http, msg, msglen); 525 CX_TEST_ASSERT(st->buf->space[2] == '\n');
482 UCX_TEST_ASSERT(w == 0, "write 2: wrong return value"); 526
483 UCX_TEST_ASSERT(st->buf->size == 2, "write 2: wrong buf size"); 527 w = net_write(http, msg, msglen);
484 UCX_TEST_ASSERT(st->buf->space[1] == '\r', "write 2: wrong content"); 528 CX_TEST_ASSERT(w == 3);
485 529 CX_TEST_ASSERT(st->buf->size == 6);
486 // next header byte: '\n' 530 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhel\0", 7));
487 w = net_write(http, msg, msglen); 531
488 UCX_TEST_ASSERT(w == 0, "write 3: wrong return value"); 532 msg += w;
489 UCX_TEST_ASSERT(st->buf->size == 3, "write 3: wrong buf size"); 533 msglen -= w;
490 UCX_TEST_ASSERT(st->buf->space[2] == '\n', "write 3: wrong content"); 534
491 535 w = net_write(http, msg, msglen);
492 // next: content 536 CX_TEST_ASSERT(w == 3);
493 w = net_write(http, msg, msglen); 537 CX_TEST_ASSERT(st->buf->size == 9);
494 UCX_TEST_ASSERT(w == 1, "write 4: wrong return value"); 538 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello \0", 10));
495 UCX_TEST_ASSERT(st->buf->size == 4, "write 3: wrong buf size"); 539
496 UCX_TEST_ASSERT(st->buf->space[3] == msg[0], "write 3: wrong content"); 540 st->max_write = 1024;
497 541 msg += w;
498 testutil_destroy_session(sn); 542 msglen -= w;
499 testutil_iostream_destroy(st); 543
500 544 w = net_write(http, msg, msglen);
501 UCX_TEST_END; 545 CX_TEST_ASSERT(w == msglen);
502 } 546 CX_TEST_ASSERT(st->buf->size == 3 + msglen_orig + 2);
503 547 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n", st->buf->size));
504 UCX_TEST(test_io_httpstream_chunked_write_partial_data) { 548
505 Session *sn = testutil_session(); 549 testutil_destroy_session(sn);
506 550 testutil_iostream_destroy(st);
507 TestIOStream *st = testutil_iostream(2048, TRUE); 551
508 IOStream *http = httpstream_new(sn->pool, (IOStream*)st); 552 }
509 httpstream_enable_chunked_write(http); 553 }
510 554
511 UCX_TEST_BEGIN; 555 CX_TEST(test_io_httpstream_chunked_write_partial_trailer) {
512
513 memset(st->buf->space, 0, st->buf->capacity);
514
515 char *msg = "hello world!";
516 size_t msglen = strlen(msg);
517 size_t msglen_orig = msglen;
518
519 // limit first write to 3 to only write the header
520 st->max_write = 3;
521 io_set_max_writes(1);
522
523 ssize_t w = net_write(http, msg, msglen);
524
525 UCX_TEST_ASSERT(w == 0, "write 1: wrong return value");
526 UCX_TEST_ASSERT(st->buf->size == 3, "write 1: wrong buf size");
527 UCX_TEST_ASSERT(st->buf->space[0] == 'c', "write 1: wrong buf content");
528 UCX_TEST_ASSERT(st->buf->space[2] == '\n', "write 1: wrong buf content");
529
530 w = net_write(http, msg, msglen);
531 UCX_TEST_ASSERT(w == 3, "write 2: wrong return value");
532 UCX_TEST_ASSERT(st->buf->size == 6, "write 2: wrong buf size");
533 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhel\0", 7), "write 2: wrong buf content");
534
535 msg += w;
536 msglen -= w;
537
538 w = net_write(http, msg, msglen);
539 UCX_TEST_ASSERT(w == 3, "write 3: wrong return value");
540 UCX_TEST_ASSERT(st->buf->size == 9, "write 3: wrong buf size");
541 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello \0", 10), "write 3: wrong buf content");
542
543 st->max_write = 1024;
544 msg += w;
545 msglen -= w;
546
547 w = net_write(http, msg, msglen);
548 UCX_TEST_ASSERT(w == msglen, "write 4: wrong return value");
549 UCX_TEST_ASSERT(st->buf->size == 3 + msglen_orig + 2, "write 4: wrong buf size");
550 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n", st->buf->size), "write 4: wrong buf content");
551
552 testutil_destroy_session(sn);
553 testutil_iostream_destroy(st);
554
555 UCX_TEST_END;
556 }
557
558 UCX_TEST(test_io_httpstream_chunked_write_partial_trailer) {
559 Session *sn = testutil_session(); 556 Session *sn = testutil_session();
560 557
561 TestIOStream *st = testutil_iostream(2048, TRUE); 558 TestIOStream *st = testutil_iostream(2048, TRUE);
562 IOStream *http = httpstream_new(sn->pool, (IOStream*)st); 559 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
563 httpstream_enable_chunked_write(http); 560 httpstream_enable_chunked_write(http);
564 io_set_max_writes(1); 561 io_set_max_writes(1);
565 562
566 UCX_TEST_BEGIN; 563 CX_TEST_DO {
567 564
568 memset(st->buf->space, 0, st->buf->capacity); 565 memset(st->buf->space, 0, st->buf->capacity);
569 566
570 char *msg = "hello world!"; 567 char *msg = "hello world!";
571 size_t msglen = strlen(msg); 568 size_t msglen = strlen(msg);
572 569
573 char *msg2 = "newmsg"; 570 char *msg2 = "newmsg";
574 size_t msglen2 = strlen(msg2); 571 size_t msglen2 = strlen(msg2);
575 572
576 char *msg3 = "msg3"; 573 char *msg3 = "msg3";
577 size_t msglen3 = strlen(msg3); 574 size_t msglen3 = strlen(msg3);
578 575
579 st->max_write = 3 + msglen; // header + msg, but without trailer 576 st->max_write = 3 + msglen; // header + msg, but without trailer
580 577
581 ssize_t w = net_write(http, msg, msglen); 578 ssize_t w = net_write(http, msg, msglen);
582 579
583 UCX_TEST_ASSERT(w == msglen, "write 1: wrong return value"); 580 CX_TEST_ASSERT(w == msglen);
584 UCX_TEST_ASSERT(st->buf->size == 3 + msglen, "write 1: wrong buf size"); 581 CX_TEST_ASSERT(st->buf->size == 3 + msglen);
585 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\0", st->buf->size + 1), "write 1: wrong buf content"); 582 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\0", st->buf->size + 1));
586 583
587 st->max_write = 2 + 3 + msglen2; // trailer + new header + new msg, without new trailer 584 st->max_write = 2 + 3 + msglen2; // trailer + new header + new msg, without new trailer
588 585
589 w = net_write(http, msg2, msglen2); 586 w = net_write(http, msg2, msglen2);
590 UCX_TEST_ASSERT(w == msglen2, "write 2: wrong return value"); 587 CX_TEST_ASSERT(w == msglen2);
591 UCX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2, "write 2: wrong buf size"); 588 CX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2);
592 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\0", st->buf->size + 1), "write 2: wrong buf content"); 589 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\0", st->buf->size + 1));
593 590
594 // limit write to 1 byte: two writes required for trailer, net_write should return 0 591 // limit write to 1 byte: two writes required for trailer, net_write should return 0
595 st->max_write = 1; 592 st->max_write = 1;
596 593
597 w = net_write(http, "dummymsg", 8); 594 w = net_write(http, "dummymsg", 8);
598 UCX_TEST_ASSERT(w == 0, "write 3: wrong return value"); 595 CX_TEST_ASSERT(w == 0);
599 596
600 w = net_write(http, "dummymsg", 8); 597 w = net_write(http, "dummymsg", 8);
601 UCX_TEST_ASSERT(w == 0, "write 4: wrong return value"); 598 CX_TEST_ASSERT(w == 0);
602 UCX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2 + 2, "write 4: wrong buf size"); 599 CX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2 + 2);
603 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\r\n\0", st->buf->size + 1), "write 4: wrong buf content"); 600 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\r\n\0", st->buf->size + 1));
604 601
605 st->max_write = 1024; 602 st->max_write = 1024;
606 w = net_write(http, msg3, msglen3); 603 w = net_write(http, msg3, msglen3);
607 604
608 UCX_TEST_ASSERT(w == msglen3, "write 5: wrong return value"); 605 CX_TEST_ASSERT(w == msglen3);
609 UCX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2 + 2 + 3 + msglen3 + 2, "write 5: wrong buf size"); 606 CX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2 + 2 + 3 + msglen3 + 2);
610 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\r\n4\r\nmsg3\r\n", st->buf->size + 1), "write 5: wrong buf content"); 607 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\r\n4\r\nmsg3\r\n", st->buf->size + 1));
611 608
612 609
613 testutil_destroy_session(sn); 610 testutil_destroy_session(sn);
614 testutil_iostream_destroy(st); 611 testutil_iostream_destroy(st);
615 612
616 UCX_TEST_END; 613 }
617 } 614 }
618 615
619 UCX_TEST(test_io_httpstream_chunked_write_partial_trailer_partial_header) { 616 CX_TEST(test_io_httpstream_chunked_write_partial_trailer_partial_header) {
620 Session *sn = testutil_session(); 617 Session *sn = testutil_session();
621 618
622 TestIOStream *st = testutil_iostream(2048, TRUE); 619 TestIOStream *st = testutil_iostream(2048, TRUE);
623 IOStream *http = httpstream_new(sn->pool, (IOStream*)st); 620 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
624 httpstream_enable_chunked_write(http); 621 httpstream_enable_chunked_write(http);
625 io_set_max_writes(1); 622 io_set_max_writes(1);
626 623
627 UCX_TEST_BEGIN; 624 CX_TEST_DO {
628 625
629 memset(st->buf->space, 0, st->buf->capacity); 626 memset(st->buf->space, 0, st->buf->capacity);
630 627
631 char *msg = "hello world!"; 628 char *msg = "hello world!";
632 size_t msglen = strlen(msg); 629 size_t msglen = strlen(msg);
633 630
634 char *msg2 = "newmsg"; 631 char *msg2 = "newmsg";
635 size_t msglen2 = strlen(msg2); 632 size_t msglen2 = strlen(msg2);
636 633
637 // Test: write partial trailer followed by partial header write 634 // Test: write partial trailer followed by partial header write
638 635
639 st->max_write = 3 + msglen + 1; 636 st->max_write = 3 + msglen + 1;
640 637
641 ssize_t w = net_write(http, msg, msglen); 638 ssize_t w = net_write(http, msg, msglen);
642 639
643 UCX_TEST_ASSERT(w == msglen, "write 1: wrong return value"); 640 CX_TEST_ASSERT(w == msglen);
644 UCX_TEST_ASSERT(st->buf->size == 3 + msglen + 1, "write 1: wrong buf size"); 641 CX_TEST_ASSERT(st->buf->size == 3 + msglen + 1);
645 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\0", st->buf->size + 1), "write 1: wrong buf content"); 642 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\0", st->buf->size + 1));
646 643
647 st->max_write = 2; // write 1 trailer byte and 1 header byte 644 st->max_write = 2; // write 1 trailer byte and 1 header byte
648 645
649 w = net_write(http, msg2, msglen2); 646 w = net_write(http, msg2, msglen2);
650 647
651 UCX_TEST_ASSERT(w == 0, "write 2: wrong return value"); 648 CX_TEST_ASSERT(w == 0);
652 UCX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 1, "write 2: wrong buf size"); 649 CX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 1);
653 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\0", st->buf->size + 1), "write 2: wrong buf content"); 650 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\0", st->buf->size + 1));
654 651
655 // force partial header write again 652 // force partial header write again
656 st->max_write = 1; 653 st->max_write = 1;
657 654
658 w = net_write(http, msg2, msglen2); 655 w = net_write(http, msg2, msglen2);
659 656
660 UCX_TEST_ASSERT(w == 0, "write 3: wrong return value"); 657 CX_TEST_ASSERT(w == 0);
661 UCX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 2, "write 3: wrong buf size"); 658 CX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 2);
662 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\0", st->buf->size + 1), "write 3: wrong buf content"); 659 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\0", st->buf->size + 1));
663 660
664 st->max_write = 1024; 661 st->max_write = 1024;
665 662
666 w = net_write(http, msg2, msglen2); 663 w = net_write(http, msg2, msglen2);
667 664
668 UCX_TEST_ASSERT(w ==msglen2, "write 4: wrong return value"); 665 CX_TEST_ASSERT(w ==msglen2);
669 UCX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2 + 2, "write 4: wrong buf size"); 666 CX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2 + 2);
670 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\r\n", st->buf->size + 1), "write 4: wrong buf content"); 667 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\r\n", st->buf->size + 1));
671 668
672 669
673 testutil_destroy_session(sn); 670 testutil_destroy_session(sn);
674 testutil_iostream_destroy(st); 671 testutil_iostream_destroy(st);
675 672
676 UCX_TEST_END; 673 }
677 } 674 }
678 675
679 UCX_TEST(test_io_httpstream_chunked_write_data_2x) { 676 CX_TEST(test_io_httpstream_chunked_write_data_2x) {
680 Session *sn = testutil_session(); 677 Session *sn = testutil_session();
681 678
682 TestIOStream *st = testutil_iostream(2048, TRUE); 679 TestIOStream *st = testutil_iostream(2048, TRUE);
683 IOStream *http = httpstream_new(sn->pool, (IOStream*)st); 680 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
684 httpstream_enable_chunked_write(http); 681 httpstream_enable_chunked_write(http);
685 io_set_max_writes(1); 682 io_set_max_writes(1);
686 683
687 UCX_TEST_BEGIN; 684 CX_TEST_DO {
688 685
689 memset(st->buf->space, 0, st->buf->capacity); 686 memset(st->buf->space, 0, st->buf->capacity);
690 687
691 // Test: First write a partial header, which forces a chunk with a specific 688 // Test: First write a partial header, which forces a chunk with a specific
692 // size. After that, write a message, that is bigger than the first 689 // size. After that, write a message, that is bigger than the first
693 // chunk, forcing a start of a second chunk, in one big writev op. 690 // chunk, forcing a start of a second chunk, in one big writev op.
694 691
695 char *msg = "hello world!"; 692 char *msg = "hello world!";
696 size_t msglen = strlen(msg); 693 size_t msglen = strlen(msg);
697 694
698 char *msg2 = "newmsg"; 695 char *msg2 = "newmsg";
699 size_t msglen2 = strlen(msg2); 696 size_t msglen2 = strlen(msg2);
700 697
701 char *msg_big = "hello world!newmsg"; 698 char *msg_big = "hello world!newmsg";
702 size_t msglen_big = strlen(msg_big); 699 size_t msglen_big = strlen(msg_big);
703 700
704 st->max_write = 1; 701 st->max_write = 1;
705 702
706 ssize_t w = net_write(http, msg, msglen); // first chunk: msg 703 ssize_t w = net_write(http, msg, msglen); // first chunk: msg
707 704
708 UCX_TEST_ASSERT(w == 0, "write 1: wrong return value"); 705 CX_TEST_ASSERT(w == 0);
709 UCX_TEST_ASSERT(st->buf->size == 1, "write 1: wrong buf size"); 706 CX_TEST_ASSERT(st->buf->size == 1);
710 707
711 st->max_write = 1024; 708 st->max_write = 1024;
712 709
713 w = net_write(http, msg_big, msglen_big); // first chunk + new chunk 710 w = net_write(http, msg_big, msglen_big); // first chunk + new chunk
714 711
715 UCX_TEST_ASSERT(w == msglen_big, "write 2: wrong return value"); 712 CX_TEST_ASSERT(w == msglen_big);
716 UCX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2 + 2, "write 2: wrong buf size"); 713 CX_TEST_ASSERT(st->buf->size == 3 + msglen + 2 + 3 + msglen2 + 2);
717 UCX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\r\n", st->buf->size + 1), "write 2: wrong buf content"); 714 CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n6\r\nnewmsg\r\n", st->buf->size + 1));
718 715
719 716
720 testutil_destroy_session(sn); 717 testutil_destroy_session(sn);
721 testutil_iostream_destroy(st); 718 testutil_iostream_destroy(st);
722 719
723 UCX_TEST_END; 720 }
724 } 721 }
725 722
726 UCX_TEST(test_io_httpstream_chunked_write_xx_limit) { 723 CX_TEST(test_io_httpstream_chunked_write_xx_limit) {
727 Session *sn = testutil_session(); 724 Session *sn = testutil_session();
728 725
729 TestIOStream *st = testutil_iostream(2048, TRUE); 726 TestIOStream *st = testutil_iostream(2048, TRUE);
730 IOStream *http = httpstream_new(sn->pool, (IOStream*)st); 727 IOStream *http = httpstream_new(sn->pool, (IOStream*)st);
731 httpstream_enable_chunked_write(http); 728 httpstream_enable_chunked_write(http);
732 io_set_max_writes(1); 729 io_set_max_writes(1);
733 730
734 UCX_TEST_BEGIN; 731 CX_TEST_DO {
735 732
736 // Test: create testdata and write it in varying chunk sizes, but 733 // Test: create testdata and write it in varying chunk sizes, but
737 // limit TestIOStream to 1 to 3 byte writes 734 // limit TestIOStream to 1 to 3 byte writes
738 735
739 // create test data 736 // create test data
740 CxBuffer *testdata = cxBufferCreate(NULL, 1024*16, cxDefaultAllocator, 0); 737 CxBuffer *testdata = cxBufferCreate(NULL, 1024*16, cxDefaultAllocator, 0);
741 for(size_t i=0;i<testdata->capacity;i++) { 738 for(size_t i=0;i<testdata->capacity;i++) {
742 cxBufferPut(testdata, 35+(i%91)); 739 cxBufferPut(testdata, 35+(i%91));
743 }
744
745 st->max_write = 1;
746
747 size_t pos = 0;
748 int chunksize = 1;
749 while(pos < testdata->size) {
750 size_t available = testdata->size - pos;
751
752 char *chunk = testdata->space + pos;
753 size_t chunklen = chunksize > available ? available : chunksize;
754
755 // write chunk
756 size_t chunkpos = 0;
757 int max_writes = chunklen + 24; // max number of write attempts
758 int writes = 0;
759 while(chunkpos < chunklen) {
760 ssize_t w = net_write(http, chunk+chunkpos, chunklen-chunkpos);
761 UCX_TEST_ASSERT(w >= 0, "net_write failed");
762 chunkpos += w;
763
764 writes++;
765 UCX_TEST_ASSERT(writes < max_writes, "max writes attempts reached");
766 } 740 }
767 741
768 pos += chunklen; 742 st->max_write = 1;
769 chunksize += 5; 743
770 744 size_t pos = 0;
771 // increase max write size at some point 745 int chunksize = 1;
772 if(pos + chunksize >= testdata->size) { 746 while(pos < testdata->size) {
773 st->max_write = INT_MAX; 747 size_t available = testdata->size - pos;
774 } else if(pos > 1024*2) { 748
775 if(pos < 1024*8) { 749 char *chunk = testdata->space + pos;
776 st->max_write = 2; 750 size_t chunklen = chunksize > available ? available : chunksize;
777 } else { 751
778 st->max_write = 3; 752 // write chunk
753 size_t chunkpos = 0;
754 int max_writes = chunklen + 24; // max number of write attempts
755 int writes = 0;
756 while(chunkpos < chunklen) {
757 ssize_t w = net_write(http, chunk+chunkpos, chunklen-chunkpos);
758 CX_TEST_ASSERT(w >= 0);
759 chunkpos += w;
760
761 writes++;
762 CX_TEST_ASSERT(writes < max_writes);
763 }
764
765 pos += chunklen;
766 chunksize += 5;
767
768 // increase max write size at some point
769 if(pos + chunksize >= testdata->size) {
770 st->max_write = INT_MAX;
771 } else if(pos > 1024*2) {
772 if(pos < 1024*8) {
773 st->max_write = 2;
774 } else {
775 st->max_write = 3;
776 }
779 } 777 }
780 } 778 }
781 } 779
782 780 // terminate chunk
783 // terminate chunk 781 net_finish(http);
784 net_finish(http); 782
785 783
786 784 // same code as test_io_httpstream_chunked_write_xx
787 // same code as test_io_httpstream_chunked_write_xx 785
788 786 // make sure the output is correctly encoded
789 // make sure the output is correctly encoded 787 // extract chunks from st->buf by using http_stream_parse_chunk_header
790 // extract chunks from st->buf by using http_stream_parse_chunk_header 788 // (which should be well-tested)
791 // (which should be well-tested) 789
792 790 WSBool first_chunk = TRUE;
793 WSBool first_chunk = TRUE; 791 int64_t chunklen = 0;
794 int64_t chunklen = 0; 792
795 793 char *buf = st->buf->space;
796 char *buf = st->buf->space; 794 size_t bufsize = st->buf->size;
797 size_t bufsize = st->buf->size; 795
798 796 pos = 0; // st->buf position
799 pos = 0; // st->buf position 797 size_t srcpos = 0; // testdata position
800 size_t srcpos = 0; // testdata position 798 int debug_counter = 0;
801 int debug_counter = 0; 799 while(pos < bufsize) {
802 while(pos < bufsize) { 800 ssize_t remaining = bufsize - pos;
803 ssize_t remaining = bufsize - pos; 801 ssize_t src_remaining = testdata->size - srcpos;
804 ssize_t src_remaining = testdata->size - srcpos; 802
805 803 int ret = http_stream_parse_chunk_header(buf+pos, remaining, first_chunk, &chunklen);
806 int ret = http_stream_parse_chunk_header(buf+pos, remaining, first_chunk, &chunklen); 804 first_chunk = FALSE;
807 first_chunk = FALSE; 805
808 806 // ret must always be > 0 (0: incomplete chunk header, -1: invalid syntax)
809 // ret must always be > 0 (0: incomplete chunk header, -1: invalid syntax) 807 CX_TEST_ASSERT(ret > 0);
810 UCX_TEST_ASSERT(ret > 0, "http_stream_parse_chunk_header ret <= 0"); 808 if(chunklen == 0) {
811 if(chunklen == 0) { 809 CX_TEST_ASSERT(src_remaining == 0);
812 UCX_TEST_ASSERT(src_remaining == 0, "stream end reached but src_remaining > 0"); 810 break;
813 break; 811 }
812
813 CX_TEST_ASSERT(chunklen <= src_remaining);
814
815 char *src_chunk = testdata->space+srcpos;
816 char *buf_chunk = buf+pos+ret;
817
818 CX_TEST_ASSERT(!memcmp(buf_chunk, src_chunk, chunklen));
819
820 pos += ret + chunklen;
821 srcpos += chunklen;
822
823 debug_counter++;
814 } 824 }
815 825
816 UCX_TEST_ASSERT(chunklen <= src_remaining, "chunklen > src_remaining"); 826
817 827 testutil_destroy_session(sn);
818 char *src_chunk = testdata->space+srcpos; 828 testutil_iostream_destroy(st);
819 char *buf_chunk = buf+pos+ret; 829 cxBufferFree(testdata);
820 830
821 UCX_TEST_ASSERT(!memcmp(buf_chunk, src_chunk, chunklen), "memcmp failed"); 831 }
822 832 }
823 pos += ret + chunklen;
824 srcpos += chunklen;
825
826 debug_counter++;
827 }
828
829
830 testutil_destroy_session(sn);
831 testutil_iostream_destroy(st);
832 cxBufferFree(testdata);
833
834 UCX_TEST_END;
835 }

mercurial