Return to test_fetch_http.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / tests / suites |
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: }