mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-17 02:56:08 +03:00
Allow actions to be unit tested.
Allow unit tests to be performance tested. Add an example script to generate @rx vs @pm tests.
This commit is contained in:
parent
cfeb3b9769
commit
40fba3355e
@ -275,6 +275,7 @@ AC_CONFIG_FILES([Makefile])
|
|||||||
AC_CONFIG_FILES([build/apxs-wrapper], [chmod +x build/apxs-wrapper])
|
AC_CONFIG_FILES([build/apxs-wrapper], [chmod +x build/apxs-wrapper])
|
||||||
if test -e "$PERL"; then
|
if test -e "$PERL"; then
|
||||||
AC_CONFIG_FILES([t/run-tests.pl], [chmod +x t/run-tests.pl])
|
AC_CONFIG_FILES([t/run-tests.pl], [chmod +x t/run-tests.pl])
|
||||||
|
AC_CONFIG_FILES([t/gen_rx-pm.pl], [chmod +x t/gen_rx-pm.pl])
|
||||||
|
|
||||||
# Perl based tools
|
# Perl based tools
|
||||||
AC_CONFIG_FILES([../tools/rules-updater.pl], [chmod +x ../tools/rules-updater.pl])
|
AC_CONFIG_FILES([../tools/rules-updater.pl], [chmod +x ../tools/rules-updater.pl])
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <apr.h>
|
#include <apr.h>
|
||||||
|
#include <apr_getopt.h>
|
||||||
|
|
||||||
#include "modsecurity.h"
|
#include "modsecurity.h"
|
||||||
#include "re.h"
|
#include "re.h"
|
||||||
@ -16,7 +17,7 @@
|
|||||||
|
|
||||||
#define ISHEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F')))
|
#define ISHEX(X) (((X >= '0')&&(X <= '9')) || ((X >= 'a')&&(X <= 'f')) || ((X >= 'A')&&(X <= 'F')))
|
||||||
|
|
||||||
#define BUFLEN 8192
|
#define BUFLEN 32768
|
||||||
|
|
||||||
#define RESULT_SUCCESS 0
|
#define RESULT_SUCCESS 0
|
||||||
#define RESULT_ERROR -1
|
#define RESULT_ERROR -1
|
||||||
@ -24,10 +25,50 @@
|
|||||||
#define RESULT_WRONGSIZE -3
|
#define RESULT_WRONGSIZE -3
|
||||||
#define RESULT_WRONGRET -4
|
#define RESULT_WRONGRET -4
|
||||||
|
|
||||||
|
#define CMDLINE_OPTS "t:n:p:P:r:I:D:h"
|
||||||
|
|
||||||
|
/* Types */
|
||||||
|
typedef struct tfn_data_t tfn_data_t;
|
||||||
|
typedef struct op_data_t op_data_t;
|
||||||
|
typedef struct action_data_t action_data_t;
|
||||||
|
|
||||||
|
struct tfn_data_t {
|
||||||
|
const char *name;
|
||||||
|
const char *param;
|
||||||
|
unsigned char *input;
|
||||||
|
apr_size_t input_len;
|
||||||
|
msre_tfn_metadata *metadata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct op_data_t {
|
||||||
|
const char *name;
|
||||||
|
const char *param;
|
||||||
|
unsigned char *input;
|
||||||
|
apr_size_t input_len;
|
||||||
|
msre_ruleset *ruleset;
|
||||||
|
msre_rule *rule;
|
||||||
|
msre_var *var;
|
||||||
|
msre_op_metadata *metadata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct action_data_t {
|
||||||
|
const char *name;
|
||||||
|
unsigned char *input;
|
||||||
|
apr_size_t input_len;
|
||||||
|
msre_ruleset *ruleset;
|
||||||
|
msre_rule *rule;
|
||||||
|
msre_var *var;
|
||||||
|
msre_actionset *actionset;
|
||||||
|
msre_action *action;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
|
static int debuglog_level = 0;
|
||||||
static char *test_name = NULL;
|
static char *test_name = NULL;
|
||||||
static apr_pool_t *g_mp = NULL;
|
static apr_pool_t *g_mp = NULL;
|
||||||
static modsec_rec *g_msr = NULL;
|
static modsec_rec *g_msr = NULL;
|
||||||
|
static unsigned char buf[BUFLEN];
|
||||||
msc_engine *modsecurity = NULL;
|
msc_engine *modsecurity = NULL;
|
||||||
|
|
||||||
|
|
||||||
@ -145,42 +186,48 @@ static char *escape(unsigned char *str, apr_size_t *len)
|
|||||||
|
|
||||||
/* Testing functions */
|
/* Testing functions */
|
||||||
|
|
||||||
static int test_tfn(const char *name, unsigned char *input, apr_size_t input_len, unsigned char **rval, apr_size_t *rval_len, char **errmsg)
|
static int init_tfn(tfn_data_t *data, const char *name, unsigned char *input, apr_size_t input_len, char **errmsg) {
|
||||||
{
|
|
||||||
int rc = -1;
|
|
||||||
msre_tfn_metadata *metadata = NULL;
|
|
||||||
|
|
||||||
*errmsg = NULL;
|
*errmsg = NULL;
|
||||||
|
|
||||||
/* Lookup the tfn */
|
data->name = name;
|
||||||
metadata = msre_engine_tfn_resolve(modsecurity->msre, name);
|
data->input = apr_pmemdup(g_mp, input, input_len);
|
||||||
|
data->input_len = input_len;
|
||||||
if (metadata == NULL) {
|
data->metadata = msre_engine_tfn_resolve(modsecurity->msre, name);
|
||||||
|
if (data->metadata == NULL) {
|
||||||
*errmsg = apr_psprintf(g_mp, "Failed to fetch tfn \"%s\".", name);
|
*errmsg = apr_psprintf(g_mp, "Failed to fetch tfn \"%s\".", name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_tfn(tfn_data_t *data, unsigned char **rval, apr_size_t *rval_len, char **errmsg)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
*errmsg = NULL;
|
||||||
|
|
||||||
/* Execute the tfn */
|
/* Execute the tfn */
|
||||||
rc = metadata->execute(g_mp, input, (long)input_len, (char **)rval, (long *)rval_len);
|
rc = data->metadata->execute(g_mp, data->input, (long)(data->input_len), (char **)rval, (long *)rval_len);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
*errmsg = apr_psprintf(g_mp, "Failed to execute tfn \"%s\".", name);
|
*errmsg = apr_psprintf(g_mp, "Failed to execute tfn \"%s\".", data->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_op(const char *name, const char *param, const unsigned char *input, apr_size_t input_len, char **errmsg)
|
static int init_op(op_data_t *data, const char *name, const char *param, unsigned char *input, apr_size_t input_len, char **errmsg) {
|
||||||
{
|
|
||||||
const char *args = apr_psprintf(g_mp, "@%s %s", name, param);
|
const char *args = apr_psprintf(g_mp, "@%s %s", name, param);
|
||||||
char *conf_fn;
|
char *conf_fn;
|
||||||
msre_ruleset *ruleset = NULL;
|
|
||||||
msre_rule *rule = NULL;
|
|
||||||
msre_var *var = NULL;
|
|
||||||
msre_op_metadata *metadata = NULL;
|
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
*errmsg = NULL;
|
*errmsg = NULL;
|
||||||
|
|
||||||
|
data->name = name;
|
||||||
|
data->param = param;
|
||||||
|
data->input = input;
|
||||||
|
data->input_len = input_len;
|
||||||
|
|
||||||
if ( apr_filepath_merge(&conf_fn, NULL, "t/unit-test.conf", APR_FILEPATH_TRUENAME, g_mp) != APR_SUCCESS) {
|
if ( apr_filepath_merge(&conf_fn, NULL, "t/unit-test.conf", APR_FILEPATH_TRUENAME, g_mp) != APR_SUCCESS) {
|
||||||
*errmsg = apr_psprintf(g_mp, "Failed to build a conf filename.");
|
*errmsg = apr_psprintf(g_mp, "Failed to build a conf filename.");
|
||||||
return -1;
|
return -1;
|
||||||
@ -198,49 +245,136 @@ static int test_op(const char *name, const char *param, const unsigned char *inp
|
|||||||
);
|
);
|
||||||
|
|
||||||
/* Lookup the operator */
|
/* Lookup the operator */
|
||||||
metadata = msre_engine_op_resolve(modsecurity->msre, name);
|
data->metadata = msre_engine_op_resolve(modsecurity->msre, name);
|
||||||
if (metadata == NULL) {
|
if (data->metadata == NULL) {
|
||||||
*errmsg = apr_psprintf(g_mp, "Failed to fetch op \"%s\".", name);
|
*errmsg = apr_psprintf(g_mp, "Failed to fetch op \"%s\".", name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a ruleset/rule */
|
/* Create a ruleset/rule */
|
||||||
ruleset = msre_ruleset_create(modsecurity->msre, g_mp);
|
data->ruleset = msre_ruleset_create(modsecurity->msre, g_mp);
|
||||||
if (ruleset == NULL) {
|
if (data->ruleset == NULL) {
|
||||||
*errmsg = apr_psprintf(g_mp, "Failed to create ruleset for op \"%s\".", name);
|
*errmsg = apr_psprintf(g_mp, "Failed to create ruleset for op \"%s\".", name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
rule = msre_rule_create(ruleset, RULE_TYPE_NORMAL, conf_fn, 1, "UNIT_TEST", args, "t:none,pass,nolog", errmsg);
|
data->rule = msre_rule_create(data->ruleset, RULE_TYPE_NORMAL, conf_fn, 1, "UNIT_TEST", args, "t:none,pass,nolog", errmsg);
|
||||||
if (rule == NULL) {
|
if (data->rule == NULL) {
|
||||||
*errmsg = apr_psprintf(g_mp, "Failed to create rule for op \"%s\": %s", name, *errmsg);
|
*errmsg = apr_psprintf(g_mp, "Failed to create rule for op \"%s\": %s", name, *errmsg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a fake variable */
|
/* Create a fake variable */
|
||||||
var = (msre_var *)apr_pcalloc(g_mp, sizeof(msre_var));
|
data->var = (msre_var *)apr_pcalloc(g_mp, sizeof(msre_var));
|
||||||
var->name = "UNIT_TEST";
|
data->var->name = "UNIT_TEST";
|
||||||
var->value = apr_pstrmemdup(g_mp, (char *)input, input_len);
|
data->var->value = apr_pstrmemdup(g_mp, (char *)input, input_len);
|
||||||
var->value_len = input_len;
|
data->var->value_len = input_len;
|
||||||
var->metadata = msre_resolve_var(modsecurity->msre, var->name);
|
data->var->metadata = msre_resolve_var(modsecurity->msre, data->var->name);
|
||||||
if (var->metadata == NULL) {
|
if (data->var->metadata == NULL) {
|
||||||
*errmsg = apr_psprintf(g_mp, "Failed to resolve variable for op \"%s\": %s", name, var->name);
|
*errmsg = apr_psprintf(g_mp, "Failed to resolve variable for op \"%s\": %s", name, data->var->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the operator parameter */
|
/* Initialize the operator parameter */
|
||||||
if (metadata->param_init != NULL) {
|
if (data->metadata->param_init != NULL) {
|
||||||
rc = metadata->param_init(rule, errmsg);
|
rc = data->metadata->param_init(data->rule, errmsg);
|
||||||
if (rc <= 0) {
|
if (rc <= 0) {
|
||||||
*errmsg = apr_psprintf(g_mp, "Failed to init op \"%s\": %s", name, *errmsg);
|
*errmsg = apr_psprintf(g_mp, "Failed to init op \"%s\": %s", name, *errmsg);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_op(op_data_t *data, char **errmsg)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
*errmsg = NULL;
|
||||||
|
|
||||||
/* Execute the operator */
|
/* Execute the operator */
|
||||||
if (metadata->execute != NULL) {
|
if (data->metadata->execute != NULL) {
|
||||||
rc = metadata->execute(g_msr, rule, var, errmsg);
|
rc = data->metadata->execute(g_msr, data->rule, data->var, errmsg);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
*errmsg = apr_psprintf(g_mp, "Failed to execute op \"%s\": %s", name, *errmsg);
|
*errmsg = apr_psprintf(g_mp, "Failed to execute op \"%s\": %s", data->name, *errmsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_action(action_data_t *data, const char *name, const char *param, char **errmsg)
|
||||||
|
{
|
||||||
|
const char *action_string = NULL;
|
||||||
|
char *conf_fn;
|
||||||
|
|
||||||
|
*errmsg = NULL;
|
||||||
|
|
||||||
|
if ((param == NULL) || (strcmp("", param) == 0)) {
|
||||||
|
action_string = apr_psprintf(g_mp, "%s", name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
action_string = apr_psprintf(g_mp, "%s:%s", name, param);
|
||||||
|
}
|
||||||
|
if (action_string == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to build action string for action: \"%s\".", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( apr_filepath_merge(&conf_fn, NULL, "t/unit-test.conf", APR_FILEPATH_TRUENAME, g_mp) != APR_SUCCESS) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to build a conf filename.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register UNIT_TEST variable */
|
||||||
|
msre_engine_variable_register(modsecurity->msre,
|
||||||
|
"UNIT_TEST",
|
||||||
|
VAR_SIMPLE,
|
||||||
|
0, 0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
VAR_DONT_CACHE,
|
||||||
|
PHASE_REQUEST_HEADERS
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Create a ruleset/rule */
|
||||||
|
data->ruleset = msre_ruleset_create(modsecurity->msre, g_mp);
|
||||||
|
if (data->ruleset == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to create ruleset for action \"%s\".", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data->rule = msre_rule_create(data->ruleset, RULE_TYPE_NORMAL, conf_fn, 1, "UNIT_TEST", "@unconditionalMatch", action_string, errmsg);
|
||||||
|
if (data->rule == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to create rule for action \"%s\": %s", name, *errmsg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the actionset/action */
|
||||||
|
data->actionset = data->rule->actionset;
|
||||||
|
if (data->actionset == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to fetch actionset for action \"%s\"", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data->action = (msre_action *)apr_table_get(data->actionset->actions, name);
|
||||||
|
if (data->action == NULL) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to fetch action for action \"%s\"", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_action(action_data_t *data, char **errmsg)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
*errmsg = NULL;
|
||||||
|
|
||||||
|
/* Execute the action */
|
||||||
|
if (data->action->metadata->execute != NULL) {
|
||||||
|
rc = data->action->metadata->execute(g_msr, g_mp, data->rule, data->action);
|
||||||
|
if (rc < 0) {
|
||||||
|
*errmsg = apr_psprintf(g_mp, "Failed to execute action \"%s\": %d", data->name, rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +399,7 @@ static void init_msr() {
|
|||||||
dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
|
dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
|
||||||
dcfg->debuglog_fd = NOT_SET_P;
|
dcfg->debuglog_fd = NOT_SET_P;
|
||||||
dcfg->debuglog_name = "msc-test-debug.log";
|
dcfg->debuglog_name = "msc-test-debug.log";
|
||||||
dcfg->debuglog_level = 9;
|
dcfg->debuglog_level = debuglog_level;
|
||||||
dcfg->cookie_format = 0;
|
dcfg->cookie_format = 0;
|
||||||
dcfg->argument_separator = '&';
|
dcfg->argument_separator = '&';
|
||||||
dcfg->rule_inheritance = 0;
|
dcfg->rule_inheritance = 0;
|
||||||
@ -282,7 +416,7 @@ static void init_msr() {
|
|||||||
dcfg->upload_dir = NULL;
|
dcfg->upload_dir = NULL;
|
||||||
dcfg->upload_keep_files = KEEP_FILES_OFF;
|
dcfg->upload_keep_files = KEEP_FILES_OFF;
|
||||||
dcfg->upload_validates_files = 0;
|
dcfg->upload_validates_files = 0;
|
||||||
dcfg->data_dir = NULL;
|
dcfg->data_dir = ".";
|
||||||
dcfg->webappid = "default";
|
dcfg->webappid = "default";
|
||||||
dcfg->content_injection_enabled = 0;
|
dcfg->content_injection_enabled = 0;
|
||||||
dcfg->pdfp_enabled = 0;
|
dcfg->pdfp_enabled = 0;
|
||||||
@ -323,50 +457,126 @@ static void init_msr() {
|
|||||||
g_msr->hostname = "localhost";
|
g_msr->hostname = "localhost";
|
||||||
g_msr->msc_rule_mptmp = g_mp;
|
g_msr->msc_rule_mptmp = g_mp;
|
||||||
g_msr->tx_vars = apr_table_make(g_mp, 10);
|
g_msr->tx_vars = apr_table_make(g_mp, 10);
|
||||||
|
g_msr->collections = apr_table_make(g_mp, 10);
|
||||||
|
g_msr->collections_dirty = apr_table_make(g_mp, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usage text.
|
||||||
|
*/
|
||||||
|
static void usage() {
|
||||||
|
fprintf(stderr, "ModSecurity Unit Tester v%s\n", MODULE_RELEASE);
|
||||||
|
fprintf(stderr, " Usage: msc_test [options]\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
fprintf(stderr, " Options:\n");
|
||||||
|
fprintf(stderr, " -t Type (required)\n");
|
||||||
|
fprintf(stderr, " -n Name (required)\n");
|
||||||
|
fprintf(stderr, " -p Parameter (required)\n");
|
||||||
|
fprintf(stderr, " -P Prerun (optional for actions)\n");
|
||||||
|
fprintf(stderr, " -r Function return code (required for some types)\n");
|
||||||
|
fprintf(stderr, " -I Iterations (default 1)\n");
|
||||||
|
fprintf(stderr, " -D Debug log level (default 0)\n");
|
||||||
|
fprintf(stderr, " -h This help\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Main */
|
/* Main */
|
||||||
|
|
||||||
int main(int argc, const char * const argv[])
|
int main(int argc, const char * const argv[])
|
||||||
{
|
{
|
||||||
|
apr_getopt_t *opt;
|
||||||
apr_file_t *fd;
|
apr_file_t *fd;
|
||||||
unsigned char buf[BUFLEN];
|
apr_size_t nbytes = 0;
|
||||||
apr_size_t nbytes = BUFLEN;
|
|
||||||
unsigned char input[BUFLEN];
|
|
||||||
const char *type = NULL;
|
const char *type = NULL;
|
||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
unsigned char *param = NULL;
|
unsigned char *param = NULL;
|
||||||
|
unsigned char *prerun = NULL;
|
||||||
const char *returnval = NULL;
|
const char *returnval = NULL;
|
||||||
|
int iterations = 1;
|
||||||
char *errmsg = NULL;
|
char *errmsg = NULL;
|
||||||
unsigned char *out = NULL;
|
unsigned char *out = NULL;
|
||||||
apr_size_t input_len = 0;
|
|
||||||
apr_size_t param_len = 0;
|
apr_size_t param_len = 0;
|
||||||
|
apr_size_t prerun_len = 0;
|
||||||
apr_size_t out_len = 0;
|
apr_size_t out_len = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int ec = 0;
|
int ec = 0;
|
||||||
|
int i;
|
||||||
|
apr_time_t T0 = 0;
|
||||||
|
apr_time_t T1 = 0;
|
||||||
|
tfn_data_t tfn_data;
|
||||||
|
op_data_t op_data;
|
||||||
|
action_data_t action_data;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
memset(&tfn_data, 0, sizeof(tfn_data_t));
|
||||||
|
memset(&op_data, 0, sizeof(op_data_t));
|
||||||
|
memset(&action_data, 0, sizeof(action_data_t));
|
||||||
|
|
||||||
apr_app_initialize(&argc, &argv, NULL);
|
apr_app_initialize(&argc, &argv, NULL);
|
||||||
atexit(apr_terminate);
|
atexit(apr_terminate);
|
||||||
|
|
||||||
if (argc < 4) {
|
apr_pool_create(&g_mp, NULL);
|
||||||
fprintf(stderr, "Usage: %s <type> <name> <param> [<returnval>]\n", argv[0]);
|
|
||||||
|
rc = apr_getopt_init(&opt, g_mp, argc, argv);
|
||||||
|
if (rc != APR_SUCCESS) {
|
||||||
|
fprintf(stderr, "Failed to initialize.\n\n");
|
||||||
|
usage();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_pool_create(&g_mp, NULL);
|
do {
|
||||||
modsecurity = modsecurity_create(g_mp, MODSEC_OFFLINE);
|
char ch;
|
||||||
|
const char *val;
|
||||||
type = argv[1];
|
rc = apr_getopt(opt, CMDLINE_OPTS, &ch, &val);
|
||||||
name = argv[2];
|
switch (rc) {
|
||||||
param_len = strlen(argv[3]);
|
case APR_SUCCESS:
|
||||||
param = apr_pmemdup(g_mp, argv[3], param_len + 1);
|
switch (ch) {
|
||||||
|
case 't':
|
||||||
|
type = val;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
name = val;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
param_len = strlen(val);
|
||||||
|
param = apr_pmemdup(g_mp, val, param_len + 1);
|
||||||
unescape_inplace(param, ¶m_len);
|
unescape_inplace(param, ¶m_len);
|
||||||
if (argc >= 5) {
|
break;
|
||||||
returnval = argv[4];
|
case 'P':
|
||||||
|
prerun_len = strlen(val);
|
||||||
|
prerun = apr_pmemdup(g_mp, val, prerun_len + 1);
|
||||||
|
unescape_inplace(prerun, &prerun_len);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
returnval = val;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
iterations = atoi(val);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
debuglog_level = atoi(val);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
usage();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case APR_BADCH:
|
||||||
|
case APR_BADARG:
|
||||||
|
usage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} while (rc != APR_EOF);
|
||||||
|
|
||||||
|
rc = apr_getopt_init(&opt, g_mp, argc, argv);
|
||||||
|
if (!type || !name || !param) {
|
||||||
|
usage();
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modsecurity = modsecurity_create(g_mp, MODSEC_OFFLINE);
|
||||||
test_name = apr_psprintf(g_mp, "%s/%s", type, name);
|
test_name = apr_psprintf(g_mp, "%s/%s", type, name);
|
||||||
|
|
||||||
if (apr_file_open_stdin(&fd, g_mp) != APR_SUCCESS) {
|
if (apr_file_open_stdin(&fd, g_mp) != APR_SUCCESS) {
|
||||||
@ -374,7 +584,9 @@ int main(int argc, const char * const argv[])
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(buf, 0, BUFLEN);
|
/* Read in the input */
|
||||||
|
nbytes = BUFLEN;
|
||||||
|
memset(buf, 0, nbytes);
|
||||||
rc = apr_file_read(fd, buf, &nbytes);
|
rc = apr_file_read(fd, buf, &nbytes);
|
||||||
if ((rc != APR_EOF) && (rc != APR_SUCCESS)) {
|
if ((rc != APR_EOF) && (rc != APR_SUCCESS)) {
|
||||||
fprintf(stderr, "Failed to read data\n");
|
fprintf(stderr, "Failed to read data\n");
|
||||||
@ -388,14 +600,89 @@ int main(int argc, const char * const argv[])
|
|||||||
|
|
||||||
apr_file_close(fd);
|
apr_file_close(fd);
|
||||||
|
|
||||||
/* Make a copy as transformations are done in-place */
|
if (strcmp("tfn", type) == 0) {
|
||||||
memcpy(input, buf, BUFLEN);
|
ret = returnval ? atoi(returnval) : -8888;
|
||||||
input_len = nbytes;
|
|
||||||
|
rc = init_tfn(&tfn_data, name, buf, nbytes, &errmsg);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "ERROR: %s\n", errmsg);
|
||||||
|
result = RESULT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp("op", type) == 0) {
|
||||||
|
if (!returnval) {
|
||||||
|
fprintf(stderr, "Return value required for type \"%s\"\n", type);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = atoi(returnval);
|
||||||
|
|
||||||
|
init_msr();
|
||||||
|
|
||||||
|
rc = init_op(&op_data, name, (const char *)param, buf, nbytes, &errmsg);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "ERROR: %s\n", errmsg);
|
||||||
|
result = RESULT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp("action", type) == 0) {
|
||||||
|
if (!returnval) {
|
||||||
|
fprintf(stderr, "Return value required for type \"%s\"\n", type);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = atoi(returnval);
|
||||||
|
|
||||||
|
init_msr();
|
||||||
|
|
||||||
|
if (prerun) {
|
||||||
|
action_data_t paction_data;
|
||||||
|
char *pname = apr_pstrdup(g_mp, (const char *)prerun);
|
||||||
|
char *pparam = NULL;
|
||||||
|
|
||||||
|
if ((pparam = strchr((const char *)pname, ':'))) {
|
||||||
|
pparam[0] = '\0';
|
||||||
|
pparam++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = init_action(&paction_data, pname, (const char *)pparam, &errmsg);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "ERROR: prerun - %s\n", errmsg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = test_action(&paction_data, &errmsg);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "ERROR: prerun - %s\n", errmsg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = init_action(&action_data, name, (const char *)param, &errmsg);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "ERROR: %s\n", errmsg);
|
||||||
|
result = RESULT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iterations > 1) {
|
||||||
|
apr_time_clock_hires (g_mp);
|
||||||
|
T0 = apr_time_now();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1; i <= iterations; i++) {
|
||||||
|
#ifdef VERBOSE
|
||||||
|
if (i % 100 == 0) {
|
||||||
|
if (i == 100) {
|
||||||
|
fprintf(stderr, "Iterations/100: .");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (strcmp("tfn", type) == 0) {
|
if (strcmp("tfn", type) == 0) {
|
||||||
/* Transformations */
|
/* Transformations */
|
||||||
int ret = returnval ? atoi(returnval) : -8888;
|
rc = test_tfn(&tfn_data, &out, &out_len, &errmsg);
|
||||||
rc = test_tfn(name, input, input_len, &out, &out_len, &errmsg);
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
fprintf(stderr, "ERROR: %s\n", errmsg);
|
fprintf(stderr, "ERROR: %s\n", errmsg);
|
||||||
result = RESULT_ERROR;
|
result = RESULT_ERROR;
|
||||||
@ -429,17 +716,7 @@ int main(int argc, const char * const argv[])
|
|||||||
}
|
}
|
||||||
else if (strcmp("op", type) == 0) {
|
else if (strcmp("op", type) == 0) {
|
||||||
/* Operators */
|
/* Operators */
|
||||||
int ret = 0;
|
rc = test_op(&op_data, &errmsg);
|
||||||
|
|
||||||
if (!returnval) {
|
|
||||||
fprintf(stderr, "Return value required for type \"%s\"\n", type);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
ret = atoi(returnval);
|
|
||||||
|
|
||||||
init_msr();
|
|
||||||
|
|
||||||
rc = test_op(name, (const char *)param, (const unsigned char *)input, input_len, &errmsg);
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
fprintf(stderr, "ERROR: %s\n", errmsg);
|
fprintf(stderr, "ERROR: %s\n", errmsg);
|
||||||
result = RESULT_ERROR;
|
result = RESULT_ERROR;
|
||||||
@ -462,11 +739,74 @@ int main(int argc, const char * const argv[])
|
|||||||
ec = 1;
|
ec = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp("action", type) == 0) {
|
||||||
|
/* Actions */
|
||||||
|
int n;
|
||||||
|
const apr_array_header_t *arr;
|
||||||
|
apr_table_entry_t *te;
|
||||||
|
|
||||||
|
rc = test_action(&action_data, &errmsg);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "ERROR: %s\n", errmsg);
|
||||||
|
result = RESULT_ERROR;
|
||||||
|
}
|
||||||
|
else if (rc != ret) {
|
||||||
|
fprintf(stderr, "Returned %d (expected %d)\n", rc, ret);
|
||||||
|
result = RESULT_WRONGRET;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != RESULT_SUCCESS) {
|
||||||
|
apr_size_t s0len = nbytes;
|
||||||
|
const char *s0 = escape(buf, &s0len);
|
||||||
|
|
||||||
|
fprintf(stderr, " Test: '@%s %s'\n"
|
||||||
|
"Input: '%s' len=%" APR_SIZE_T_FMT "\n",
|
||||||
|
name, param, s0, nbytes);
|
||||||
|
ec = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store any collections that were initialized and changed */
|
||||||
|
arr = apr_table_elts(g_msr->collections);
|
||||||
|
te = (apr_table_entry_t *)arr->elts;
|
||||||
|
for (n = 0; n < arr->nelts; n++) {
|
||||||
|
apr_table_t *col = (apr_table_t *)te[n].val;
|
||||||
|
|
||||||
|
msr_log(g_msr, 9, "Found loaded collection: %s", te[n].key);
|
||||||
|
/* Only store those collections that changed. */
|
||||||
|
if (apr_table_get(g_msr->collections_dirty, te[n].key)) {
|
||||||
|
msr_log(g_msr, 9, "Storing collection: %s", te[n].key);
|
||||||
|
collection_store(g_msr, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "Unknown type: \"%s\"\n", type);
|
fprintf(stderr, "Unknown type: \"%s\"\n", type);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ec != 0) {
|
||||||
|
fprintf(stdout, "%s\n", errmsg ? errmsg : "");
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iterations > 1) {
|
||||||
|
double dT;
|
||||||
|
T1 = apr_time_now();
|
||||||
|
|
||||||
|
dT = apr_time_as_msec(T1 - T0);
|
||||||
|
|
||||||
|
#ifdef VERBOSE
|
||||||
|
if (i >= 100) {
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fprintf(stdout, "%d @ %.4f msec per iteration.\n", iterations, dT / iterations);
|
||||||
|
}
|
||||||
fprintf(stdout, "%s\n", errmsg ? errmsg : "");
|
fprintf(stdout, "%s\n", errmsg ? errmsg : "");
|
||||||
|
|
||||||
return ec;
|
return ec;
|
||||||
|
96
apache2/t/gen_rx-pm.pl.in
Executable file
96
apache2/t/gen_rx-pm.pl.in
Executable file
@ -0,0 +1,96 @@
|
|||||||
|
#!@PERL@
|
||||||
|
#
|
||||||
|
# Generates a test file for comparing @rx and @pm speed.
|
||||||
|
#
|
||||||
|
use strict;
|
||||||
|
use Regexp::Assemble;
|
||||||
|
|
||||||
|
|
||||||
|
my $MIN = 1;
|
||||||
|
my $MAX = 5000;
|
||||||
|
my $INC = 250;
|
||||||
|
my $ITERATIONS = 10000;
|
||||||
|
my $MINSTRLEN = 2;
|
||||||
|
my $MAXSTRLEN = 8;
|
||||||
|
|
||||||
|
my $last = rndstr();
|
||||||
|
my @param = ($last);
|
||||||
|
my $i=$MIN;
|
||||||
|
while ($i <= $MAX) {
|
||||||
|
my $ra = Regexp::Assemble->new;
|
||||||
|
$ra->add(@param);
|
||||||
|
|
||||||
|
printf (
|
||||||
|
"# rx: %6d\n".
|
||||||
|
"{\n".
|
||||||
|
" comment => \"%6d item(s)\",\n".
|
||||||
|
" type => \"op\",\n".
|
||||||
|
" name => \"rx\",\n".
|
||||||
|
" param => qr/^(?:%s)\$/,\n".
|
||||||
|
" input => \"%s\",\n".
|
||||||
|
" ret => 1,\n".
|
||||||
|
" iterations => %d,\n".
|
||||||
|
"},\n",
|
||||||
|
$i,
|
||||||
|
$i,
|
||||||
|
join('|', @param),
|
||||||
|
$last,
|
||||||
|
$ITERATIONS,
|
||||||
|
);
|
||||||
|
|
||||||
|
printf (
|
||||||
|
"# rx-optimized: %6d\n".
|
||||||
|
"{\n".
|
||||||
|
" comment => \"%6d item(s)\",\n".
|
||||||
|
" type => \"op\",\n".
|
||||||
|
" name => \"rx\",\n".
|
||||||
|
" param => qr/^(?:%s)\$/,\n".
|
||||||
|
" input => \"%s\",\n".
|
||||||
|
" ret => 1,\n".
|
||||||
|
" iterations => %d,\n".
|
||||||
|
"},\n",
|
||||||
|
$i,
|
||||||
|
$i,
|
||||||
|
$ra->as_string,
|
||||||
|
$last,
|
||||||
|
$ITERATIONS,
|
||||||
|
);
|
||||||
|
|
||||||
|
printf (
|
||||||
|
"# pm: %6d\n".
|
||||||
|
"{\n".
|
||||||
|
" comment => \"%6d item(s)\",\n".
|
||||||
|
" type => \"op\",\n".
|
||||||
|
" name => \"pm\",\n".
|
||||||
|
" param => \"%s\",\n".
|
||||||
|
" input => \"%s\",\n".
|
||||||
|
" ret => 1,\n".
|
||||||
|
" iterations => %d,\n".
|
||||||
|
"},\n",
|
||||||
|
$i,
|
||||||
|
$i,
|
||||||
|
join(' ', @param),
|
||||||
|
$last,
|
||||||
|
$ITERATIONS,
|
||||||
|
);
|
||||||
|
|
||||||
|
$i = ($i == 1) ? $INC : $i + $INC;
|
||||||
|
|
||||||
|
while (@param < $i) {
|
||||||
|
unshift @param, rndstr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub rndstr {
|
||||||
|
my @c=('a'..'z','0'..'9','_');
|
||||||
|
my $rndstr;
|
||||||
|
my $max = int(rand($MAXSTRLEN - $MINSTRLEN)) + $MINSTRLEN;
|
||||||
|
foreach (1 .. $max) {
|
||||||
|
$rndstr .= $c[rand @c];
|
||||||
|
}
|
||||||
|
# We need a string that is not in another string for "last"
|
||||||
|
if ($last =~ m/$rndstr/) {
|
||||||
|
$rndstr = rndstr();
|
||||||
|
}
|
||||||
|
return $rndstr;
|
||||||
|
}
|
@ -13,12 +13,13 @@ use File::Basename qw(basename dirname);
|
|||||||
use FileHandle;
|
use FileHandle;
|
||||||
use IPC::Open2 qw(open2);
|
use IPC::Open2 qw(open2);
|
||||||
|
|
||||||
my @TYPES = qw(tfn op);
|
my @TYPES = qw(tfn op action);
|
||||||
my $TEST = "./msc_test";
|
my $TEST = "./msc_test";
|
||||||
my $SCRIPT = basename($0);
|
my $SCRIPT = basename($0);
|
||||||
my $SCRIPTDIR = dirname($0);
|
my $SCRIPTDIR = dirname($0);
|
||||||
my $PASSED = 0;
|
my $PASSED = 0;
|
||||||
my $TOTAL = 0;
|
my $TOTAL = 0;
|
||||||
|
my $DEBUG = $ENV{MSC_TEST_DEBUG} || 0;
|
||||||
|
|
||||||
if (defined $ARGV[0]) {
|
if (defined $ARGV[0]) {
|
||||||
runfile(dirname($ARGV[0]), basename($ARGV[0]), $ARGV[1]);
|
runfile(dirname($ARGV[0]), basename($ARGV[0]), $ARGV[1]);
|
||||||
@ -72,7 +73,7 @@ sub runfile {
|
|||||||
|
|
||||||
my %t = %{$t || {}};
|
my %t = %{$t || {}};
|
||||||
my $id = sprintf("%6d", $n);
|
my $id = sprintf("%6d", $n);
|
||||||
my $in = $t{input};
|
my $in = (exists($t{input}) and defined($t{input})) ? $t{input} : "";
|
||||||
my $out;
|
my $out;
|
||||||
my $test_in = new FileHandle();
|
my $test_in = new FileHandle();
|
||||||
my $test_out = new FileHandle();
|
my $test_out = new FileHandle();
|
||||||
@ -86,11 +87,14 @@ sub runfile {
|
|||||||
elsif ($t{type} eq "op") {
|
elsif ($t{type} eq "op") {
|
||||||
$param = escape($t{param});
|
$param = escape($t{param});
|
||||||
}
|
}
|
||||||
|
elsif ($t{type} eq "action") {
|
||||||
|
$param = escape($t{param});
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
quit(1, "Unknown type \"$t{type}\" - should be one of: " . join(",",@TYPES));
|
quit(1, "Unknown type \"$t{type}\" - should be one of: " . join(",",@TYPES));
|
||||||
}
|
}
|
||||||
|
|
||||||
@test = ($t{type}, $t{name}, $param, (exists($t{ret}) ? ($t{ret}) : ()));
|
@test = ("-t", $t{type}, "-n", $t{name}, "-p", $param, "-D", "$DEBUG", (exists($t{ret}) ? ("-r", $t{ret}) : ()), (exists($t{iterations}) ? ("-I", $t{iterations}) : ()), (exists($t{prerun}) ? ("-P", $t{prerun}) : ()));
|
||||||
$teststr = "$TEST " . join(" ", map { "\"$_\"" } @test);
|
$teststr = "$TEST " . join(" ", map { "\"$_\"" } @test);
|
||||||
$test_pid = open2($test_out, $test_in, $TEST, @test) or quit(1, "Failed to execute test: $teststr\": $!");
|
$test_pid = open2($test_out, $test_in, $TEST, @test) or quit(1, "Failed to execute test: $teststr\": $!");
|
||||||
print $test_in "$in";
|
print $test_in "$in";
|
||||||
@ -117,7 +121,7 @@ sub runfile {
|
|||||||
$pass++;
|
$pass++;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg(sprintf("%s) %s \"%s\": %s%s", $id, $t{type}, $t{name}, ($rc ? "failed" : "passed"), ((defined($out) && $out ne "")? " ($out)" : "")));
|
msg(sprintf("%s) %s \"%s\"%s: %s%s", $id, $t{type}, $t{name}, (exists($t{comment}) ? " $t{comment}" : ""), ($rc ? "failed" : "passed"), ((defined($out) && $out ne "")? " ($out)" : "")));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user