|
@@ -3010,21 +3010,6 @@ START_TEST(test_error_handling)
|
|
|
|
|
|
char bad_thread_num[32] = "badnumber";
|
|
char bad_thread_num[32] = "badnumber";
|
|
|
|
|
|
- const char *OPTIONS[] = {
|
|
|
|
-#if !defined(NO_FILES)
|
|
|
|
- "document_root",
|
|
|
|
- ".",
|
|
|
|
-#endif
|
|
|
|
- "error_pages",
|
|
|
|
- "./",
|
|
|
|
- "listening_ports",
|
|
|
|
- "8080",
|
|
|
|
- "num_threads",
|
|
|
|
- bad_thread_num,
|
|
|
|
- "unknown_option",
|
|
|
|
- "unknown_option_value",
|
|
|
|
- NULL
|
|
|
|
- };
|
|
|
|
struct mg_callbacks callbacks;
|
|
struct mg_callbacks callbacks;
|
|
char errmsg[256];
|
|
char errmsg[256];
|
|
|
|
|
|
@@ -3033,6 +3018,23 @@ START_TEST(test_error_handling)
|
|
const struct mg_request_info *client_ri;
|
|
const struct mg_request_info *client_ri;
|
|
int client_res, i;
|
|
int client_res, i;
|
|
|
|
|
|
|
|
+ const char *OPTIONS[32];
|
|
|
|
+ int opt_cnt = 0;
|
|
|
|
+
|
|
|
|
+#if !defined(NO_FILES)
|
|
|
|
+ OPTIONS[opt_cnt++] = "document_root";
|
|
|
|
+ OPTIONS[opt_cnt++] = ".";
|
|
|
|
+#endif
|
|
|
|
+ OPTIONS[opt_cnt++] = "error_pages";
|
|
|
|
+ OPTIONS[opt_cnt++] = "./";
|
|
|
|
+ OPTIONS[opt_cnt++] = "listening_ports";
|
|
|
|
+ OPTIONS[opt_cnt++] = "8080";
|
|
|
|
+ OPTIONS[opt_cnt++] = "num_threads";
|
|
|
|
+ OPTIONS[opt_cnt++] = bad_thread_num;
|
|
|
|
+ OPTIONS[opt_cnt++] = "unknown_option";
|
|
|
|
+ OPTIONS[opt_cnt++] = "unknown_option_value";
|
|
|
|
+ OPTIONS[opt_cnt] = NULL;
|
|
|
|
+
|
|
memset(&callbacks, 0, sizeof(callbacks));
|
|
memset(&callbacks, 0, sizeof(callbacks));
|
|
|
|
|
|
callbacks.log_message = log_msg_func;
|
|
callbacks.log_message = log_msg_func;
|
|
@@ -3264,6 +3266,151 @@ START_TEST(test_error_handling)
|
|
END_TEST
|
|
END_TEST
|
|
|
|
|
|
|
|
|
|
|
|
+static int
|
|
|
|
+test_throttle_begin_request(struct mg_connection *conn)
|
|
|
|
+{
|
|
|
|
+ const struct mg_request_info *ri;
|
|
|
|
+ long unsigned len = 1024 * 10;
|
|
|
|
+ const char *block = "0123456789";
|
|
|
|
+ unsigned long i, blocklen;
|
|
|
|
+
|
|
|
|
+ ck_assert(conn != NULL);
|
|
|
|
+ ri = mg_get_request_info(conn);
|
|
|
|
+ ck_assert(ri != NULL);
|
|
|
|
+
|
|
|
|
+ ck_assert_str_eq(ri->request_method, "GET");
|
|
|
|
+ ck_assert_str_eq(ri->request_uri, "/throttle");
|
|
|
|
+ ck_assert_str_eq(ri->local_uri, "/throttle");
|
|
|
|
+ ck_assert_str_eq(ri->http_version, "1.0");
|
|
|
|
+ ck_assert_str_eq(ri->query_string, "q");
|
|
|
|
+ ck_assert_str_eq(ri->remote_addr, "127.0.0.1");
|
|
|
|
+
|
|
|
|
+ mg_printf(conn,
|
|
|
|
+ "HTTP/1.1 200 OK\r\n"
|
|
|
|
+ "Content-Length: %lu\r\n"
|
|
|
|
+ "Connection: close\r\n\r\n",
|
|
|
|
+ len);
|
|
|
|
+
|
|
|
|
+ blocklen = (unsigned long)strlen(block);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < len; i += blocklen) {
|
|
|
|
+ mg_write(conn, block, blocklen);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 987; /* Not a valid HTTP response code,
|
|
|
|
+ * but it should be written to the log and passed to
|
|
|
|
+ * end_request. */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+test_throttle_end_request(const struct mg_connection *conn,
|
|
|
|
+ int reply_status_code)
|
|
|
|
+{
|
|
|
|
+ const struct mg_request_info *ri;
|
|
|
|
+
|
|
|
|
+ ck_assert(conn != NULL);
|
|
|
|
+ ri = mg_get_request_info(conn);
|
|
|
|
+ ck_assert(ri != NULL);
|
|
|
|
+
|
|
|
|
+ ck_assert_str_eq(ri->request_method, "GET");
|
|
|
|
+ ck_assert_str_eq(ri->request_uri, "/throttle");
|
|
|
|
+ ck_assert_str_eq(ri->local_uri, "/throttle");
|
|
|
|
+ ck_assert_str_eq(ri->http_version, "1.0");
|
|
|
|
+ ck_assert_str_eq(ri->query_string, "q");
|
|
|
|
+ ck_assert_str_eq(ri->remote_addr, "127.0.0.1");
|
|
|
|
+
|
|
|
|
+ ck_assert_int_eq(reply_status_code, 987);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+START_TEST(test_throttle)
|
|
|
|
+{
|
|
|
|
+ /* Server var */
|
|
|
|
+ struct mg_context *ctx;
|
|
|
|
+ struct mg_callbacks callbacks;
|
|
|
|
+ const char *OPTIONS[32];
|
|
|
|
+ int opt_cnt = 0;
|
|
|
|
+
|
|
|
|
+ /* Client var */
|
|
|
|
+ struct mg_connection *client;
|
|
|
|
+ char client_err_buf[256];
|
|
|
|
+ char client_data_buf[256];
|
|
|
|
+ const struct mg_request_info *client_ri;
|
|
|
|
+
|
|
|
|
+ /* timing test */
|
|
|
|
+ int r, data_read;
|
|
|
|
+ time_t t0, t1;
|
|
|
|
+ double dt;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/* Set options and start server */
|
|
|
|
+#if !defined(NO_FILES)
|
|
|
|
+ OPTIONS[opt_cnt++] = "document_root";
|
|
|
|
+ OPTIONS[opt_cnt++] = ".";
|
|
|
|
+#endif
|
|
|
|
+ OPTIONS[opt_cnt++] = "listening_ports";
|
|
|
|
+ OPTIONS[opt_cnt++] = "8080";
|
|
|
|
+ OPTIONS[opt_cnt++] = "throttle";
|
|
|
|
+ OPTIONS[opt_cnt++] = "*=1k";
|
|
|
|
+ OPTIONS[opt_cnt] = NULL;
|
|
|
|
+
|
|
|
|
+ memset(&callbacks, 0, sizeof(callbacks));
|
|
|
|
+ callbacks.begin_request = test_throttle_begin_request;
|
|
|
|
+ callbacks.end_request = test_throttle_end_request;
|
|
|
|
+
|
|
|
|
+ ctx = test_mg_start(&callbacks, 0, OPTIONS);
|
|
|
|
+ ck_assert(ctx != NULL);
|
|
|
|
+
|
|
|
|
+ /* connect client */
|
|
|
|
+ memset(client_err_buf, 0, sizeof(client_err_buf));
|
|
|
|
+ memset(client_data_buf, 0, sizeof(client_data_buf));
|
|
|
|
+
|
|
|
|
+ strcpy(client_err_buf, "reset-content");
|
|
|
|
+ client = mg_download("127.0.0.1",
|
|
|
|
+ 8080,
|
|
|
|
+ 0,
|
|
|
|
+ client_err_buf,
|
|
|
|
+ sizeof(client_err_buf),
|
|
|
|
+ "GET /throttle?q HTTP/1.0\r\n\r\n");
|
|
|
|
+
|
|
|
|
+ ck_assert(ctx != NULL);
|
|
|
|
+ ck_assert_str_eq(client_err_buf, "");
|
|
|
|
+
|
|
|
|
+ client_ri = mg_get_request_info(client);
|
|
|
|
+
|
|
|
|
+ ck_assert(client_ri != NULL);
|
|
|
|
+ ck_assert_str_eq(client_ri->uri, "200");
|
|
|
|
+
|
|
|
|
+ ck_assert_int_eq(client_ri->content_length, 1024 * 10);
|
|
|
|
+
|
|
|
|
+ data_read = 0;
|
|
|
|
+ t0 = time(NULL);
|
|
|
|
+ while (data_read < client_ri->content_length) {
|
|
|
|
+ r = mg_read(client, client_data_buf, sizeof(client_data_buf));
|
|
|
|
+ ck_assert_int_ge(r, 0);
|
|
|
|
+ data_read += r;
|
|
|
|
+ }
|
|
|
|
+ t1 = time(NULL);
|
|
|
|
+ dt = difftime(t1, t0) * 1000.0; /* Elapsed time in ms - in most systems
|
|
|
|
+ * only with second resolution */
|
|
|
|
+
|
|
|
|
+ /* Check if there are at least 10 seconds */
|
|
|
|
+ ck_assert_int_ge((int)dt, 10 * 1000);
|
|
|
|
+
|
|
|
|
+ /* Nothing left to read */
|
|
|
|
+ r = mg_read(client, client_data_buf, sizeof(client_data_buf));
|
|
|
|
+ ck_assert_int_eq(r, 0);
|
|
|
|
+
|
|
|
|
+ /* Close the client connection */
|
|
|
|
+ mg_close_connection(client);
|
|
|
|
+
|
|
|
|
+ /* Stop the server */
|
|
|
|
+ test_mg_stop(ctx);
|
|
|
|
+}
|
|
|
|
+END_TEST
|
|
|
|
+
|
|
|
|
+
|
|
Suite *
|
|
Suite *
|
|
make_public_server_suite(void)
|
|
make_public_server_suite(void)
|
|
{
|
|
{
|
|
@@ -3279,6 +3426,8 @@ make_public_server_suite(void)
|
|
TCase *const tcase_http_auth = tcase_create("HTTP Authentication");
|
|
TCase *const tcase_http_auth = tcase_create("HTTP Authentication");
|
|
TCase *const tcase_keep_alive = tcase_create("HTTP Keep Alive");
|
|
TCase *const tcase_keep_alive = tcase_create("HTTP Keep Alive");
|
|
TCase *const tcase_error_handling = tcase_create("Error handling");
|
|
TCase *const tcase_error_handling = tcase_create("Error handling");
|
|
|
|
+ TCase *const tcase_throttle = tcase_create("Limit speed");
|
|
|
|
+
|
|
|
|
|
|
tcase_add_test(tcase_checktestenv, test_the_test_environment);
|
|
tcase_add_test(tcase_checktestenv, test_the_test_environment);
|
|
tcase_set_timeout(tcase_checktestenv, civetweb_min_test_timeout);
|
|
tcase_set_timeout(tcase_checktestenv, civetweb_min_test_timeout);
|
|
@@ -3320,6 +3469,10 @@ make_public_server_suite(void)
|
|
tcase_set_timeout(tcase_error_handling, 300);
|
|
tcase_set_timeout(tcase_error_handling, 300);
|
|
suite_add_tcase(suite, tcase_error_handling);
|
|
suite_add_tcase(suite, tcase_error_handling);
|
|
|
|
|
|
|
|
+ tcase_add_test(tcase_throttle, test_throttle);
|
|
|
|
+ tcase_set_timeout(tcase_throttle, 300);
|
|
|
|
+ suite_add_tcase(suite, tcase_throttle);
|
|
|
|
+
|
|
return suite;
|
|
return suite;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3345,6 +3498,7 @@ MAIN_PUBLIC_SERVER(void)
|
|
test_http_auth(0);
|
|
test_http_auth(0);
|
|
test_keep_alive(0);
|
|
test_keep_alive(0);
|
|
test_error_handling(0);
|
|
test_error_handling(0);
|
|
|
|
+ test_throttle(0);
|
|
|
|
|
|
printf("\nok: %i\nfailed: %i\n\n", chk_ok, chk_failed);
|
|
printf("\nok: %i\nfailed: %i\n\n", chk_ok, chk_failed);
|
|
}
|
|
}
|