Annotation of embedaddon/strongswan/src/libstrongswan/tests/suites/test_fetch_http.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2014 Martin Willi
3: * Copyright (C) 2014 revosec AG
4: *
5: * This program is free software; you can redistribute it and/or modify it
6: * under the terms of the GNU General Public License as published by the
7: * Free Software Foundation; either version 2 of the License, or (at your
8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9: *
10: * This program is distributed in the hope that it will be useful, but
11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13: * for more details.
14: */
15:
16: #include "test_suite.h"
17:
18: #include <unistd.h>
19: #include <time.h>
20:
21: #define HTTP_SUCCESS(status) ((status) >= 200 && (status) < 300)
22:
23: /**
24: * HTTP test definition
25: */
26: typedef struct {
27: /* HTTP Method */
28: char *meth;
29: /* HTTP 1.x minor version */
30: int minor;
31: /* host to connect to */
32: char *host;
33: /* HTTP service port */
34: int port;
35: /* path on host to fetch from */
36: char *path;
37: /* request Content-Type, if any */
38: char *type;
39: /* request data, if any */
40: void *req;
41: /* length of request data */
42: int req_len;
43: /* response data, if any */
44: void *res;
45: /* length of response data */
46: int res_len;
47: /* status code, defaults to 200 */
48: u_int code;
49: } test_service_t;
50:
51: static char large[] = {
52: 0x88,0x3e,0xa3,0xe3,0x95,0x67,0x53,0x93,0xc8,0xce,0x5c,0xcd,0x8c,0x03,0x0c,0xa8,
53: 0x94,0xaf,0x49,0xf6,0xc6,0x50,0xad,0xb8,0xea,0xb8,0x85,0x8a,0xde,0x92,0xe1,0xbc,
54: 0xf3,0x15,0xbb,0x5b,0xb8,0x35,0xd8,0x17,0xad,0xcf,0x6b,0x07,0x63,0x61,0x2e,0x2f,
55: 0xa5,0xc9,0x1d,0xa7,0xac,0xaa,0x4d,0xde,0x71,0x65,0x95,0x87,0x66,0x50,0xa2,0xa6,
56: 0x28,0xef,0x49,0x5c,0x53,0xa3,0x87,0xad,0x42,0xc3,0x41,0xd8,0xfa,0x92,0xd8,0x32,
57: 0xce,0x7c,0xf2,0x72,0x2f,0x51,0x27,0x71,0xe3,0x78,0x59,0xf9,0x46,0x23,0xf3,0xa7,
58: 0x38,0x12,0x05,0xbb,0x1a,0xb0,0xe0,0x12,0xae,0x97,0xa1,0x0f,0xd4,0x34,0xe0,0x15,
59: 0xb4,0xa3,0x15,0x08,0xbe,0xff,0x4d,0x31,0x81,0x39,0x62,0x29,0xf0,0x90,0x79,0x02,
60: 0x4d,0x0c,0xf4,0x9e,0xe5,0xd4,0xdc,0xca,0xea,0xb8,0x85,0x8a,0xde,0x92,0xe1,0xbc,
61: 0xf3,0x15,0xbb,0x5b,0xb8,0x35,0xd8,0x17,0xad,0xcf,0x6b,0x07,0x63,0x61,0x2e,0x2f,
62: 0xa5,0xc9,0x1d,0xa7,0xac,0xaa,0x4d,0xde,0x71,0x65,0x95,0x87,0x66,0x50,0xa2,0xa6,
63: 0x28,0xef,0x49,0x5c,0x53,0xa3,0x87,0xad,0x42,0xc3,0x41,0xd8,0xfa,0x92,0xd8,0x32,
64: 0xce,0x7c,0xf2,0x72,0x2f,0x51,0x27,0x71,0xe3,0x78,0x59,0xf9,0x46,0x23,0xf3,0xa7,
65: 0x38,0x12,0x05,0xbb,0x1a,0xb0,0xe0,0x12,0xae,0x97,0xa1,0x0f,0xd4,0x34,0xe0,0x15,
66: 0xf3,0x15,0xbb,0x5b,0xb8,0x35,0xd8,0x17,0xad,0xcf,0x6b,0x07,0x63,0x61,0x2e,0x2f,
67: 0xa5,0xc9,0x1d,0xa7,0xac,0xaa,0x4d,0xde,0x71,0x65,0x95,0x87,0x66,0x50,0xa2,0xa6,
68: 0x28,0xef,0x49,0x5c,0x53,0xa3,0x87,0xad,0x42,0xc3,0x41,0xd8,0xfa,0x92,0xd8,0x32,
69: 0xce,0x7c,0xf2,0x72,0x2f,0x51,0x27,0x71,0xe3,0x78,0x59,0xf9,0x46,0x23,0xf3,0xa7,
70: 0x38,0x12,0x05,0xbb,0x1a,0xb0,0xe0,0x12,0xae,0x97,0xa1,0x0f,0xd4,0x34,0xe0,0x15,
71: 0xb4,0xa3,0x15,0x08,0xbe,0xff,0x4d,0x31,0x81,0x39,0x62,0x29,0xf0,0x90,0x79,0x02,
72: 0x4d,0x0c,0xf4,0x9e,0xe5,0xd4,0xdc,0xca,0xea,0xb8,0x85,0x8a,0xde,0x92,0xe1,0xbc,
73: 0xf3,0x15,0xbb,0x5b,0xb8,0x35,0xd8,0x17,0xad,0xcf,0x6b,0x07,0x63,0x61,0x2e,0x2f,
74: 0xa5,0xc9,0x1d,0xa7,0xac,0xaa,0x4d,0xde,0x71,0x65,0x95,0x87,0x66,0x50,0xa2,0xa6,
75: 0x28,0xef,0x49,0x5c,0x53,0xa3,0x87,0xad,0x42,0xc3,0x41,0xd8,0xfa,0x92,0xd8,0x32,
76: 0xce,0x7c,0xf2,0x72,0x2f,0x51,0x27,0x71,0xe3,0x78,0x59,0xf9,0x46,0x23,0xf3,0xa7,
77: 0x38,0x12,0x05,0xbb,0x1a,0xb0,0xe0,0x12,0xae,0x97,0xa1,0x0f,0xd4,0x34,0xe0,0x15,
78: 0xb4,0xa3,0x15,0x08,0xbe,0xff,0x4d,0x31,0x81,0x39,0x62,0x29,0xf0,0x90,0x79,0x02,
79: 0x4d,0x0c,0xf4,0x9e,0xe5,0xd4,0xdc,0xca,0xea,0xb8,0x85,0x8a,0xde,0x92,0xe1,0xbc,
80: };
81:
82: static bool servicing(void *data, stream_t *stream)
83: {
84: test_service_t *test = (test_service_t*)data;
85: char buf[1024], hdr[256], *start, *end = NULL, *body = NULL, *type = NULL;
86: struct tm tm;
87: time_t t;
88: ssize_t len, tot = 0;
89: int nr = 0;
90:
91: start = buf;
92:
93: /* parse method and headers */
94: while (end != start)
95: {
96: len = stream->read(stream, buf + tot, sizeof(buf) - tot, TRUE);
97: ck_assert(len > 0);
98: tot += len;
99:
100: while (TRUE)
101: {
102: end = memchr(start, '\n', tot);
103: if (!end)
104: {
105: break;
106: }
107: *end = '\0';
108: ck_assert(end > buf);
109: ck_assert(*(--end) == '\r');
110: *end = '\0';
111: if (end == start)
112: {
113: body = end + strlen("\r\n");
114: break;
115: }
116: switch (nr++)
117: {
118: case 0:
119: snprintf(hdr, sizeof(hdr), "%s %s HTTP/1.%u",
120: test->meth, test->path, test->minor);
121: ck_assert_str_eq(hdr, start);
122: break;
123: default:
124: if (strcasepfx(start, "Content-Length: "))
125: {
126: ck_assert_int_eq(
127: atoi(start + strlen("Content-Length: ")),
128: test->req_len);
129: }
130: if (strcasepfx(start, "Content-Type: "))
131: {
132: type = start + strlen("Content-Type: ");
133: }
134: break;
135: }
136: start = end + strlen("\r\n");
137: }
138: }
139:
140: if (test->type)
141: {
142: ck_assert(type);
143: ck_assert_str_eq(type, test->type);
144: }
145:
146: /* request body */
147: if (test->req_len)
148: {
149: ck_assert(stream->read_all(stream, buf + tot,
150: test->req_len - (tot - (body - buf))));
151: ck_assert(memeq(body, test->req, test->req_len));
152: }
153:
154: if (!test->code)
155: {
156: test->code = 200;
157: }
158:
159: /* response headers */
160: snprintf(buf, sizeof(buf), "HTTP/1.%u %u OK\r\n", test->minor, test->code);
161: ck_assert(stream->write_all(stream, buf, strlen(buf)));
162:
163: /* if the response code indicates an error the following write operations
164: * might fail because the client already terminated the TCP connection */
165: #define may_fail(test, op) ck_assert(op || !HTTP_SUCCESS(test->code))
166:
167: t = time(NULL);
168: gmtime_r(&t, &tm);
169: strftime(buf, sizeof(buf), "%a, %d %b %Y %T %z", &tm);
170: may_fail(test, stream->write_all(stream, buf, strlen(buf)));
171: snprintf(buf, sizeof(buf), "Server: strongSwan unit test\r\n");
172: may_fail(test, stream->write_all(stream, buf, strlen(buf)));
173:
174: /* rest of response headers */
175: snprintf(buf, sizeof(buf), "Content-Type: text/plain\r\n");
176: may_fail(test, stream->write_all(stream, buf, strlen(buf)));
177: snprintf(buf, sizeof(buf), "Content-Length: %u\r\n", test->res_len);
178: may_fail(test, stream->write_all(stream, buf, strlen(buf)));
179: snprintf(buf, sizeof(buf), "Connection: close\r\n");
180: may_fail(test, stream->write_all(stream, buf, strlen(buf)));
181: snprintf(buf, sizeof(buf), "\r\n");
182: may_fail(test, stream->write_all(stream, buf, strlen(buf)));
183:
184: /* response body */
185: may_fail(test, stream->write_all(stream, test->res, test->res_len));
186: return FALSE;
187: }
188:
189: static test_service_t gtests[] = {
190: { "GET", 1, "127.0.0.1", 6543, "/a/test/?b=c", NULL,
191: NULL, 0, "\x12\x34", 2, 0 },
192: { "GET", 0, "localhost", 6543, "/", NULL,
193: NULL, 0, NULL, 0, 0 },
194: { "GET", 0, "127.0.0.1", 6543, "/largefile", NULL,
195: NULL, 0, large, sizeof(large), 0 },
196: { "GET", 1, "[::1]", 6543, "/ipv6-url", NULL,
197: NULL, 0, "\x00\r\n\r\x00testdatablabla", 20, 0 },
198: };
199:
200: START_TEST(test_get)
201: {
202: stream_service_t *service;
203: status_t status;
204: chunk_t data, expected;
205: char uri[256];
206:
207: lib->processor->set_threads(lib->processor, 8);
208:
209: snprintf(uri, sizeof(uri), "tcp://%s:%u", gtests[_i].host, gtests[_i].port);
210: service = lib->streams->create_service(lib->streams, uri, 1);
211: ck_assert(service != NULL);
212: service->on_accept(service, servicing, >ests[_i], JOB_PRIO_HIGH, 0);
213:
214: snprintf(uri, sizeof(uri), "http://%s:%u%s",
215: gtests[_i].host, gtests[_i].port, gtests[_i].path);
216: status = lib->fetcher->fetch(lib->fetcher, uri, &data,
217: !gtests[_i].minor ? FETCH_HTTP_VERSION_1_0 : FETCH_END,
218: FETCH_END);
219: ck_assert_int_eq(status, SUCCESS);
220: expected = chunk_create(gtests[_i].res, gtests[_i].res_len);
221: ck_assert_msg(chunk_compare(expected, data) == 0,
222: "exp %B\ngot %B\n", &expected, &data);
223: free(data.ptr);
224:
225: service->destroy(service);
226: }
227: END_TEST
228:
229:
230: static test_service_t ptests[] = {
231: { "POST", 1, "127.0.0.1", 6543, "/a/test/?b=c", "application/binary",
232: "\x23\x45", 2, "\x12\x34", 2, 0 },
233: { "POST", 0, "localhost", 6543, "/largefile", "application/x-large",
234: large, sizeof(large), large, sizeof(large), 0 },
235: { "POST", 1, "[::1]", 6543, "/ipv6-url", "text/plain",
236: "\x00\r\n\r\x00testdatablabla", 20, "\x00\r\n\r\x00testdatablabla", 20, 0 },
237: };
238:
239: START_TEST(test_post)
240: {
241: stream_service_t *service;
242: status_t status;
243: chunk_t data, expected;
244: char uri[256];
245:
246: lib->processor->set_threads(lib->processor, 8);
247:
248: snprintf(uri, sizeof(uri), "tcp://%s:%u", ptests[_i].host, ptests[_i].port);
249: service = lib->streams->create_service(lib->streams, uri, 1);
250: ck_assert(service != NULL);
251: service->on_accept(service, servicing, &ptests[_i], JOB_PRIO_HIGH, 0);
252:
253: snprintf(uri, sizeof(uri), "http://%s:%u%s",
254: ptests[_i].host, ptests[_i].port, ptests[_i].path);
255: status = lib->fetcher->fetch(lib->fetcher, uri, &data,
256: FETCH_REQUEST_TYPE, ptests[_i].type,
257: FETCH_REQUEST_DATA,
258: chunk_create(ptests[_i].req, ptests[_i].req_len),
259: !ptests[_i].minor ? FETCH_HTTP_VERSION_1_0 : FETCH_END,
260: FETCH_END);
261: ck_assert_int_eq(status, SUCCESS);
262: expected = chunk_create(ptests[_i].res, ptests[_i].res_len);
263: ck_assert_msg(chunk_compare(expected, data) == 0,
264: "exp %B\ngot %B\n", &expected, &data);
265: free(data.ptr);
266:
267: service->destroy(service);
268: }
269: END_TEST
270:
271:
272: static test_service_t rtests[] = {
273: { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 200 },
274: { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 204 },
275: { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 400 },
276: { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 404 },
277: { "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 500 },
278: };
279:
280: START_TEST(test_response_code)
281: {
282: stream_service_t *service;
283: status_t status;
284: chunk_t data = chunk_empty;
285: char uri[256];
286: u_int code;
287:
288: lib->processor->set_threads(lib->processor, 8);
289:
290: snprintf(uri, sizeof(uri), "tcp://%s:%u", rtests[_i].host, rtests[_i].port);
291: service = lib->streams->create_service(lib->streams, uri, 1);
292: ck_assert(service != NULL);
293: service->on_accept(service, servicing, &rtests[_i], JOB_PRIO_HIGH, 0);
294:
295: snprintf(uri, sizeof(uri), "http://%s:%u%s",
296: rtests[_i].host, rtests[_i].port, rtests[_i].path);
297: status = lib->fetcher->fetch(lib->fetcher, uri, &data,
298: FETCH_RESPONSE_CODE, &code, FETCH_END);
299: ck_assert_int_eq(status, HTTP_SUCCESS(rtests[_i].code) ? SUCCESS : FAILED);
300: ck_assert_int_eq(code, rtests[_i].code);
301: free(data.ptr);
302:
303: service->destroy(service);
304: }
305: END_TEST
306:
307: Suite *fetch_http_suite_create()
308: {
309: Suite *s;
310: TCase *tc;
311:
312: s = suite_create("http fetcher");
313:
314: tc = tcase_create("GET");
315: tcase_add_loop_test(tc, test_get, 0, countof(gtests));
316: test_case_set_timeout(tc, 10);
317: suite_add_tcase(s, tc);
318:
319: tc = tcase_create("POST");
320: tcase_add_loop_test(tc, test_post, 0, countof(ptests));
321: test_case_set_timeout(tc, 10);
322: suite_add_tcase(s, tc);
323:
324: tc = tcase_create("response code");
325: tcase_add_loop_test(tc, test_response_code, 0, countof(rtests));
326: test_case_set_timeout(tc, 10);
327: suite_add_tcase(s, tc);
328:
329: return s;
330: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>