diff --git a/CMakeLists.txt b/CMakeLists.txt index d206657c..ceefbf8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,12 +89,8 @@ option(CIVETWEB_ENABLE_LUA "Enable Lua CGIs" OFF) message(STATUS "Lua CGI support - ${CIVETWEB_ENABLE_LUA}") # Allow builds to complete with warnings (do not set -Werror) -#option(CIVETWEB_ALLOW_WARNINGS "Do not stop build if there are warnings" OFF) -#message(STATUS "Build if there are warnings - ${CIVETWEB_ALLOW_WARNINGS}") -# ... this option is not set by the user, but it is set if there are 3rd party components -if (CIVETWEB_ENABLE_LUA OR CIVETWEB_ENABLE_DUKTAPE) -SET(CIVETWEB_ALLOW_WARNINGS YES) -endif() +option(CIVETWEB_ALLOW_WARNINGS "Do not stop build if there are warnings" OFF) +message(STATUS "Build if there are warnings - ${CIVETWEB_ALLOW_WARNINGS}") # Link to the shared LUA library @@ -211,6 +207,11 @@ if (CIVETWEB_ENABLE_SSL_DYNAMIC_LOADING AND NOT DARWIN AND UNIX) message(STATUS "SSL Cryptography Library Name - ${CIVETWEB_SSL_CRYPTO_LIB}") endif() +# Allow warnings in 3rd party components +if (CIVETWEB_ENABLE_LUA OR CIVETWEB_ENABLE_DUKTAPE) +SET(CIVETWEB_ALLOW_WARNINGS YES) +endif() + # The C and C++ standards to use set(CIVETWEB_C_STANDARD auto CACHE STRING "The C standard to use; auto determines the latest supported by the compiler") diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f204e728..30b74eb6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -141,7 +141,7 @@ civetweb_add_test(PublicFunc "URL encoding decoding") civetweb_add_test(PublicFunc "Cookies and variables") civetweb_add_test(PublicFunc "MD5") -# Public server tests +# Public API server tests civetweb_add_test(PublicServer "Check test environment") civetweb_add_test(PublicServer "Start threads") civetweb_add_test(PublicServer "Start Stop HTTP Server") diff --git a/test/public_server.c b/test/public_server.c index aea06a40..56506ec7 100644 --- a/test/public_server.c +++ b/test/public_server.c @@ -47,29 +47,49 @@ */ static const char * -locate_ssl_cert(void) +locate_resources(void) { return #ifdef _WIN32 #ifdef LOCAL_TEST - "resources\\ssl_cert.pem"; + "resources\\"; #else /* Appveyor */ - "..\\..\\..\\resources\\ssl_cert.pem"; /* TODO: the different paths + "..\\..\\..\\resources\\"; /* TODO: the different paths * used in the different test * system is an unsolved * problem */ #endif #else #ifdef LOCAL_TEST - "resources/ssl_cert.pem"; + "resources/"; #else /* Travis */ - "../../resources/ssl_cert.pem"; // TODO: fix path in CI test environment + "../../resources/"; // TODO: fix path in CI test environment #endif #endif } + +static const char * +locate_ssl_cert(void) +{ + static char cert_path[256]; + const char *res = locate_resources(); + size_t l; + + ck_assert(res != NULL); + l = strlen(res); + ck_assert_int_gt(l, 0); + ck_assert_int_lt(l, 100); /* assume there is enough space left in our + typical 255 character string buffers */ + + strcpy(cert_path, res); + strcat(cert_path, "ssl_cert.pem"); + return cert_path; +} + + static int wait_not_null(void *volatile *data) { @@ -200,6 +220,11 @@ START_TEST(test_mg_start_stop_http_server) struct mg_callbacks callbacks; char errmsg[256]; + struct mg_connection *client_conn; + char client_err[256]; + const struct mg_request_info *client_ri; + int client_res; + memset(ports, 0, sizeof(ports)); memset(ssl, 0, sizeof(ssl)); memset(&callbacks, 0, sizeof(callbacks)); @@ -220,6 +245,28 @@ START_TEST(test_mg_start_stop_http_server) ck_assert_int_eq(ssl[1], 0); test_sleep(1); + + memset(client_err, 0, sizeof(client_err)); + client_conn = + mg_connect_client("127.0.0.1", 8080, 0, client_err, sizeof(client_err)); + ck_assert(client_conn != NULL); + ck_assert_str_eq(client_err, ""); + mg_printf(client_conn, "GET / HTTP/1.0\r\n\r\n"); + client_res = + mg_get_response(client_conn, client_err, sizeof(client_err), 10000); + ck_assert_int_ge(client_res, 0); + ck_assert_str_eq(client_err, ""); + client_ri = mg_get_request_info(client_conn); + ck_assert(client_ri != NULL); + ck_assert_str_eq(client_ri->uri, "200"); + /* TODO: ck_assert_str_eq(client_ri->request_method, "HTTP/1.0"); */ + client_res = (int)mg_read(client_conn, client_err, sizeof(client_err)); + ck_assert_int_gt(client_res, 0); + ck_assert_int_le(client_res, sizeof(client_err)); + mg_close_connection(client_conn); + + test_sleep(1); + mg_stop(ctx); } END_TEST @@ -239,6 +286,12 @@ START_TEST(test_mg_start_stop_https_server) const char *OPTIONS[8]; /* initializer list here is rejected by CI test */ int opt_idx = 0; const char *ssl_cert = locate_ssl_cert(); + + struct mg_connection *client_conn; + char client_err[256]; + const struct mg_request_info *client_ri; + int client_res; + ck_assert(ssl_cert != NULL); memset((void *)OPTIONS, 0, sizeof(OPTIONS)); @@ -277,11 +330,118 @@ START_TEST(test_mg_start_stop_https_server) ck_assert_int_eq(ssl[2], 0); test_sleep(1); + + memset(client_err, 0, sizeof(client_err)); + client_conn = + mg_connect_client("127.0.0.1", 8443, 1, client_err, sizeof(client_err)); + ck_assert(client_conn != NULL); + ck_assert_str_eq(client_err, ""); + mg_printf(client_conn, "GET / HTTP/1.0\r\n\r\n"); + client_res = + mg_get_response(client_conn, client_err, sizeof(client_err), 10000); + ck_assert_int_ge(client_res, 0); + ck_assert_str_eq(client_err, ""); + client_ri = mg_get_request_info(client_conn); + ck_assert(client_ri != NULL); + ck_assert_str_eq(client_ri->uri, "200"); + /* TODO: ck_assert_str_eq(client_ri->request_method, "HTTP/1.0"); */ + client_res = (int)mg_read(client_conn, client_err, sizeof(client_err)); + ck_assert_int_gt(client_res, 0); + ck_assert_int_le(client_res, sizeof(client_err)); + mg_close_connection(client_conn); + + test_sleep(1); + mg_stop(ctx); #endif } END_TEST + +START_TEST(test_mg_server_and_client_tls) +{ +#ifndef NO_SSL + + struct mg_context *ctx; + + size_t ports_cnt; + struct mg_server_ports ports[16]; + struct mg_callbacks callbacks; + char errmsg[256]; + + const char *OPTIONS[32]; /* initializer list here is rejected by CI test */ + int opt_idx = 0; + char server_cert[256]; + char client_cert[256]; + const char *res_dir = locate_resources(); + + ck_assert(res_dir != NULL); + strcpy(server_cert, res_dir); + strcpy(client_cert, res_dir); +#ifdef _WIN32 + strcat(server_cert, "cert\\server.pem"); + strcat(client_cert, "cert\\client.pem"); +#else + strcat(server_cert, "cert/server.pem"); + strcat(client_cert, "cert/client.pem"); +#endif + + memset((void *)OPTIONS, 0, sizeof(OPTIONS)); +#if !defined(NO_FILES) + OPTIONS[opt_idx++] = "document_root"; + OPTIONS[opt_idx++] = "."; +#endif + OPTIONS[opt_idx++] = "listening_ports"; + OPTIONS[opt_idx++] = "8080r,8443s"; + OPTIONS[opt_idx++] = "ssl_certificate"; + OPTIONS[opt_idx++] = server_cert; + OPTIONS[opt_idx++] = "ssl_verify_peer"; + OPTIONS[opt_idx++] = "yes"; + OPTIONS[opt_idx++] = "ssl_ca_file"; + OPTIONS[opt_idx++] = client_cert; + + ck_assert_int_le(opt_idx, (int)(sizeof(OPTIONS) / sizeof(OPTIONS[0]))); + ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 1] == NULL); + ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 2] == NULL); + + memset(ports, 0, sizeof(ports)); + memset(&callbacks, 0, sizeof(callbacks)); + memset(errmsg, 0, sizeof(errmsg)); + + callbacks.log_message = log_msg_func; + + ctx = mg_start(&callbacks, (void *)errmsg, OPTIONS); + test_sleep(1); + ck_assert_str_eq(errmsg, ""); + ck_assert(ctx != NULL); + + ports_cnt = mg_get_server_ports(ctx, 16, ports); + ck_assert_uint_eq(ports_cnt, 2); + ck_assert_int_eq(ports[0].protocol, 1); + ck_assert_int_eq(ports[0].port, 8080); + ck_assert_int_eq(ports[0].is_ssl, 0); + ck_assert_int_eq(ports[0].is_redirect, 1); + ck_assert_int_eq(ports[1].protocol, 1); + ck_assert_int_eq(ports[1].port, 8443); + ck_assert_int_eq(ports[1].is_ssl, 1); + ck_assert_int_eq(ports[1].is_redirect, 0); + ck_assert_int_eq(ports[2].protocol, 0); + ck_assert_int_eq(ports[2].port, 0); + ck_assert_int_eq(ports[2].is_ssl, 0); + ck_assert_int_eq(ports[2].is_redirect, 0); + + test_sleep(1); + + /* TODO: A client API using a client certificate is missing */ + + test_sleep(1); + + mg_stop(ctx); +#endif +} +END_TEST + + static struct mg_context *g_ctx; static int @@ -1087,6 +1247,8 @@ make_public_server_suite(void) TCase *const startthreads = tcase_create("Start threads"); TCase *const startstophttp = tcase_create("Start Stop HTTP Server"); TCase *const startstophttps = tcase_create("Start Stop HTTPS Server"); + TCase *const serverandclienttls = + tcase_create("Start Stop TLS Server Client"); TCase *const serverrequests = tcase_create("Server Requests"); tcase_add_test(checktestenv, test_the_test_environment); @@ -1105,6 +1267,10 @@ make_public_server_suite(void) tcase_set_timeout(startstophttps, civetweb_min_test_timeout); suite_add_tcase(suite, startstophttps); + tcase_add_test(serverandclienttls, test_mg_server_and_client_tls); + tcase_set_timeout(serverandclienttls, civetweb_min_test_timeout); + suite_add_tcase(suite, serverandclienttls); + tcase_add_test(serverrequests, test_request_handlers); tcase_set_timeout(serverrequests, 120); suite_add_tcase(suite, serverrequests); @@ -1126,6 +1292,7 @@ main(void) test_mg_start_stop_http_server(0); test_mg_start_stop_https_server(0); test_request_handlers(0); + test_mg_server_and_client_tls(0); printf("\nok: %i\nfailed: %i\n\n", chk_ok, chk_failed); }