diff options
Diffstat (limited to 'debian/perl-framework/c-modules')
18 files changed, 2280 insertions, 0 deletions
diff --git a/debian/perl-framework/c-modules/authany/mod_authany.c b/debian/perl-framework/c-modules/authany/mod_authany.c new file mode 100644 index 0000000..a5e146c --- /dev/null +++ b/debian/perl-framework/c-modules/authany/mod_authany.c @@ -0,0 +1,172 @@ +#if CONFIG_FOR_HTTPD_TEST + +Alias /authany @DocumentRoot@ +<Location /authany> + require user any-user + AuthType Basic + AuthName authany + <IfDefine !APACHE1> + <IfVersion >= 2.3> + AuthBasicProvider any + </IfVersion> + </IfDefine> +</Location> + +#endif + +#include "ap_mmn.h" + +/* do not accept empty "" strings */ +#define strtrue(s) (s && *s) + +#if AP_MODULE_MAGIC_AT_LEAST(20060110, 0) + +#include "ap_provider.h" +#include "mod_auth.h" + +static authn_status authn_check_password(request_rec *r, const char *user, + const char *password) +{ + return strtrue(r->user) && strcmp(r->user, "guest") == 0 + ? AUTH_GRANTED : AUTH_DENIED; +} + +static const authn_provider authn_any_provider = +{ + &authn_check_password +}; + +static authz_status any_check_authorization(request_rec *r, + const char *requirement, + const void *dummy) +{ +#if AP_MODULE_MAGIC_AT_LEAST(20100714,0) + if (!r->user) + return AUTHZ_DENIED_NO_USER; +#endif + + return strtrue(r->user) && strcmp(requirement, "any-user") == 0 + ? AUTHZ_GRANTED : AUTHZ_DENIED; +} + +static const authz_provider authz_any_provider = +{ + &any_check_authorization +}; + +static void extra_hooks(apr_pool_t *p) +{ + ap_register_provider(p, AUTHN_PROVIDER_GROUP, + "any", "0", &authn_any_provider); + ap_register_provider(p, AUTHZ_PROVIDER_GROUP, + "user", "0", &authz_any_provider); +} + +#define APACHE_HTTPD_TEST_EXTRA_HOOKS extra_hooks + +#include "apache_httpd_test.h" + +#else /* < 2.3 */ + +#ifdef APACHE2 + +#include "apr_pools.h" + +static void extra_hooks(apr_pool_t *); + +#define APACHE_HTTPD_TEST_EXTRA_HOOKS extra_hooks + +#else + +#define APACHE_HTTPD_TEST_HOOK_ORDER APR_HOOK_FIRST +#define APACHE_HTTPD_TEST_CHECK_USER_ID authany_handler +#define APACHE_HTTPD_TEST_AUTH_CHECKER require_any_user + +#endif + +#include "apache_httpd_test.h" + +static int require_any_user(request_rec *r) +{ + const apr_array_header_t *requires = ap_requires(r); + require_line *rq; + int x; + + if (!requires) { + return DECLINED; + } + + rq = (require_line *) requires->elts; + + for (x = 0; x < requires->nelts; x++) { + const char *line, *requirement; + + line = rq[x].requirement; + requirement = ap_getword(r->pool, &line, ' '); + + if ((strcmp(requirement, "user") == 0) && + (strcmp(line, "any-user") == 0)) + { + return OK; + } + } + + return DECLINED; +} + +static int authany_handler(request_rec *r) +{ + const char *sent_pw; + int rc = ap_get_basic_auth_pw(r, &sent_pw); + char *user; + + if (rc != OK) { + return rc; + } + + if (require_any_user(r) != OK) { + return DECLINED; + } + +#ifdef APACHE1 + user = r->connection->user; +#endif +#ifdef APACHE2 + user = r->user; +#endif + + if (!(strtrue(user) && strtrue(sent_pw))) { + ap_note_basic_auth_failure(r); +#ifdef APACHE1 + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, + "Both a username and password must be provided"); +#endif +#ifdef APACHE2 + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, + "Both a username and password must be provided"); +#endif + return HTTP_UNAUTHORIZED; + } + + return OK; +} + +#ifdef APACHE2 +static void extra_hooks(apr_pool_t *p) +{ + /* mod_authany and mod_ssl both specify APR_HOOK_FIRST as the + * ordering of their check-user-id hooks. + * mod_ssl's must run before mod_authany because it may need to + * generate the Basic auth information based on the certificate. + */ + static const char * const modssl_runs_before[] = {"mod_ssl.c", NULL}; + + ap_hook_check_user_id(authany_handler, modssl_runs_before, NULL, + APR_HOOK_FIRST); + ap_hook_auth_checker(require_any_user, NULL, NULL, APR_HOOK_FIRST); +} +#endif + +#endif + +APACHE_HTTPD_TEST_MODULE(authany); diff --git a/debian/perl-framework/c-modules/client_add_filter/mod_client_add_filter.c b/debian/perl-framework/c-modules/client_add_filter/mod_client_add_filter.c new file mode 100644 index 0000000..ce5ef99 --- /dev/null +++ b/debian/perl-framework/c-modules/client_add_filter/mod_client_add_filter.c @@ -0,0 +1,54 @@ +#define HTTPD_TEST_REQUIRE_APACHE 2 + +#include "httpd.h" +#include "http_config.h" +#include "http_protocol.h" +#include "http_request.h" +#include "http_log.h" +#include "ap_config.h" + +/* + * in real life we'd never allow the client to configure filters. + * the purpose of this module is to let .t tests configure filters + * this allows to test non-filtered and filtered requests without + * duplicating lots of test configuration + */ + +static int client_add_filter_header(void *data, + const char *key, + const char *val) +{ + request_rec *r = (request_rec *)data; + + if (strcasecmp(key, "X-AddInputFilter") == 0) { + ap_add_input_filter(val, NULL, r, r->connection); + } + else if (strcasecmp(key, "X-AddOutputFilter") == 0) { + ap_add_output_filter(val, NULL, r, r->connection); + } + + return 1; +} + +static void client_add_filter_insert(request_rec *r) +{ + apr_table_do(client_add_filter_header, (void*)r, + r->headers_in, NULL); +} + +static void client_add_filter_register_hooks(apr_pool_t *p) +{ + ap_hook_insert_filter(client_add_filter_insert, + NULL, NULL, APR_HOOK_LAST); +} + +module AP_MODULE_DECLARE_DATA client_add_filter_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + NULL, /* table of config file commands */ + client_add_filter_register_hooks /* register hooks */ +}; + diff --git a/debian/perl-framework/c-modules/eat_post/mod_eat_post.c b/debian/perl-framework/c-modules/eat_post/mod_eat_post.c new file mode 100644 index 0000000..560ba19 --- /dev/null +++ b/debian/perl-framework/c-modules/eat_post/mod_eat_post.c @@ -0,0 +1,61 @@ +#if CONFIG_FOR_HTTPD_TEST + +<Location /eat_post> + SetHandler eat_post +</Location> + +#endif + +#define APACHE_HTTPD_TEST_HANDLER eat_post_handler + +#include "apache_httpd_test.h" + +/* like mod_echo_post.c but does not echo back the data, + * just sends back the number of bytes read + */ +static int eat_post_handler(request_rec *r) +{ + int rc; + long nrd, total = 0; +#ifdef APACHE1 + char buff[IOBUFSIZE]; +#else + char buff[AP_IOBUFSIZE]; +#endif + + if (strcmp(r->handler, "eat_post")) { + return DECLINED; + } + if ((r->method_number != M_POST) && (r->method_number != M_PUT)) { + return DECLINED; + } + + if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) { +#ifdef APACHE1 + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r->server, + "[mod_eat_post] ap_setup_client_block failed: %d", rc); +#else + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r->server, + "[mod_eat_post] ap_setup_client_block failed: %d", rc); +#endif /* APACHE1 */ + return rc; + } + + if (!ap_should_client_block(r)) { + return OK; + } + +#ifdef APACHE1 + ap_send_http_header(r); +#endif + + while ((nrd = ap_get_client_block(r, buff, sizeof(buff))) > 0) { + total += nrd; + } + + ap_rprintf(r, "%ld\n", total); + + return OK; +} + +APACHE_HTTPD_TEST_MODULE(eat_post); diff --git a/debian/perl-framework/c-modules/echo_post/mod_echo_post.c b/debian/perl-framework/c-modules/echo_post/mod_echo_post.c new file mode 100644 index 0000000..ebda4d5 --- /dev/null +++ b/debian/perl-framework/c-modules/echo_post/mod_echo_post.c @@ -0,0 +1,102 @@ +#if CONFIG_FOR_HTTPD_TEST + +<Location /echo_post> + SetHandler echo_post +</Location> + +#endif + +#define APACHE_HTTPD_TEST_HANDLER echo_post_handler + +#include "apache_httpd_test.h" + +static int echo_post_handler(request_rec *r) +{ + int rc; + long nrd, total = 0; + char buff[BUFSIZ]; + + if (strcmp(r->handler, "echo_post")) { + return DECLINED; + } + if (r->method_number != M_POST) { + return DECLINED; + } + + if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) { +#ifdef APACHE1 + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r->server, + "[mod_echo_post] ap_setup_client_block failed: %d", rc); +#else + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r->server, + "[mod_echo_post] ap_setup_client_block failed: %d", rc); +#endif /* APACHE1 */ + return 0; + } + + if (!ap_should_client_block(r)) { + return OK; + } + +#ifdef APACHE1 + ap_send_http_header(r); +#endif + + if (r->args) { +#ifdef APACHE1 + ap_rprintf(r, "%ld:", r->remaining); +#else + ap_rprintf(r, "%" APR_OFF_T_FMT ":", r->remaining); +#endif /* APACHE1 */ + } + +#ifdef APACHE1 + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, r, + "[mod_echo_post] going to echo %ld bytes", + r->remaining); +#else + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "[mod_echo_post] going to echo %" APR_OFF_T_FMT " bytes", + r->remaining); +#endif /* APACHE1 */ + + while ((nrd = ap_get_client_block(r, buff, sizeof(buff))) > 0) { +#ifdef APACHE1 + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, r, + "[mod_echo_post] read %ld bytes (wanted %d, remaining=%ld)", + nrd, sizeof(buff), r->remaining); +#else + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "[mod_echo_post] read %ld bytes (wanted %" APR_SIZE_T_FMT + ", remaining=%" APR_OFF_T_FMT ")", + nrd, sizeof(buff), r->remaining); +#endif /* APACHE1 */ + ap_rwrite(buff, nrd, r); + total += nrd; + } + + if (nrd < 0) { + ap_rputs("!!!ERROR!!!", r); +#ifdef APACHE1 + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, r, + "[mod_echo_post] ap_get_client_block got error"); +#else + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "[mod_echo_post] ap_get_client_block got error"); +#endif /* APACHE1 */ + } + +#ifdef APACHE1 + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, r, + "[mod_echo_post] done reading %ld bytes, %ld bytes remain", + total, r->remaining); +#else + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "[mod_echo_post] done reading %ld bytes, %" APR_OFF_T_FMT " bytes remain", + total, r->remaining); +#endif /* APACHE1 */ + + return OK; +} + +APACHE_HTTPD_TEST_MODULE(echo_post); diff --git a/debian/perl-framework/c-modules/echo_post_chunk/mod_echo_post_chunk.c b/debian/perl-framework/c-modules/echo_post_chunk/mod_echo_post_chunk.c new file mode 100644 index 0000000..98cc4e1 --- /dev/null +++ b/debian/perl-framework/c-modules/echo_post_chunk/mod_echo_post_chunk.c @@ -0,0 +1,93 @@ +#if CONFIG_FOR_HTTPD_TEST + +<Location /echo_post_chunk> + SetHandler echo_post_chunk +</Location> + +#endif + +#define APACHE_HTTPD_TEST_HANDLER echo_post_chunk_handler + +#include "apache_httpd_test.h" + +static int echo_post_chunk_handler(request_rec *r) +{ + int rc; + long nrd, total = 0; + char buff[BUFSIZ]; + const char *trailer_header; + + if (strcmp(r->handler, "echo_post_chunk")) { + return DECLINED; + } + if (r->method_number != M_POST) { + return DECLINED; + } + + if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK) { +#ifdef APACHE1 + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r->server, + "[mod_echo_post_chunk] ap_setup_client_block failed: %d", rc); +#else + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r->server, + "[mod_echo_post_chunk] ap_setup_client_block failed: %d", rc); +#endif /* APACHE1 */ + return 0; + } + + if (!ap_should_client_block(r)) { + return OK; + } + + if (r->args) { + ap_rprintf(r, "%" APR_OFF_T_FMT ":", r->remaining); + } + + fprintf(stderr, "[mod_echo_post_chunk] going to echo " + "%" APR_OFF_T_FMT " bytes\n", + r->remaining); + + while ((nrd = ap_get_client_block(r, buff, sizeof(buff))) > 0) { + fprintf(stderr, + "[mod_echo_post_chunk] read %ld bytes " + "(wanted %" APR_SIZE_T_FMT ", remaining=%" APR_OFF_T_FMT ")\n", + nrd, sizeof(buff), r->remaining); + total += nrd; + } + + /* nrd < 0 is an error condition. Either the chunk size overflowed or the buffer + * size was insufficient. We can only deduce that the request is in error. + */ + if (nrd < 0) { + return HTTP_BAD_REQUEST; + } +#ifdef APACHE1 + ap_send_http_header(r); +#endif + +#ifdef APACHE1 + trailer_header = ap_table_get(r->headers_in, "X-Chunk-Trailer"); +#elif (MODULE_MAGIC_COOKIE >= 0x41503235UL) && AP_MODULE_MAGIC_AT_LEAST(20140627,5) + trailer_header = apr_table_get(r->trailers_in, "X-Chunk-Trailer"); +#elif (MODULE_MAGIC_COOKIE == 0x41503234UL) && AP_MODULE_MAGIC_AT_LEAST(20120211,37) + trailer_header = apr_table_get(r->trailers_in, "X-Chunk-Trailer"); +#elif (MODULE_MAGIC_COOKIE == 0x41503232UL) && AP_MODULE_MAGIC_AT_LEAST(20051115,36) + trailer_header = apr_table_get(r->trailers_in, "X-Chunk-Trailer"); +#else + trailer_header = apr_table_get(r->headers_in, "X-Chunk-Trailer"); +#endif + if (!trailer_header) { + trailer_header = "No chunked trailer available!"; + } + + ap_rputs(trailer_header, r); + + fprintf(stderr, + "[mod_echo_post_chunk] done reading %ld bytes, " + "%" APR_OFF_T_FMT " bytes remain\n", + total, r->remaining); + + return OK; +} + +APACHE_HTTPD_TEST_MODULE(echo_post_chunk); diff --git a/debian/perl-framework/c-modules/fold/mod_fold.c b/debian/perl-framework/c-modules/fold/mod_fold.c new file mode 100644 index 0000000..548cb67 --- /dev/null +++ b/debian/perl-framework/c-modules/fold/mod_fold.c @@ -0,0 +1,33 @@ +#if CONFIG_FOR_HTTPD_TEST + +<Location /fold> + SetHandler fold +</Location> + +#endif + +#define APACHE_HTTPD_TEST_HANDLER fold_handler + +#include "apache_httpd_test.h" + +static int fold_handler(request_rec *r) +{ + + if (!r->handler || strcasecmp(r->handler, "fold")) { + return DECLINED; + } + + if (r->args) { + ap_set_content_type(r, r->args); + } + else { + ap_set_content_type(r, "text/html"); + } + + /* This doesn't work with CGI or asis, hence the tiny module */ + apr_table_set(r->err_headers_out, "Foo", "Bar\r\n Baz"); + + return OK; +} + +APACHE_HTTPD_TEST_MODULE(fold); diff --git a/debian/perl-framework/c-modules/httpd_test_util.c b/debian/perl-framework/c-modules/httpd_test_util.c new file mode 100644 index 0000000..bc8e608 --- /dev/null +++ b/debian/perl-framework/c-modules/httpd_test_util.c @@ -0,0 +1,44 @@ +/* poor man's optional functions + * if we didn't need to support 1.x we could use optional functions. + * just hack in this util functions with #define/#include/static for now. + * + * tho we could create our own version optional functions using + * the 1.3/2.0 dlsym-ish function to lookup function pointers given a + * mod_httpd_test_util.so and httpd_test_util.dynamic_load_handle + * but thats more trouble than it is worth at the moment. + */ + +#ifdef WANT_HTTPD_TEST_SPLIT_QS_NUMBERS + +/* split query string in the form of GET /foo?1024,5000 */ + +static int httpd_test_split_qs_numbers(request_rec *r, ...) +{ + va_list va; + char *endptr, *args = r->args; + + if (!args) { + return 0; + } + + va_start(va, r); + + while (1) { + apr_size_t *s = va_arg(va, apr_size_t *); + if (!s) { + break; + } + *s = strtol(args, &endptr, 0); + if (endptr && (*endptr == ',')) { + ++endptr; + args = endptr; + } + } + + va_end(va); + + return 1; +} + +#endif /* WANT_HTTPD_TEST_SPLIT_QS_NUMBERS */ + diff --git a/debian/perl-framework/c-modules/input_body_filter/mod_input_body_filter.c b/debian/perl-framework/c-modules/input_body_filter/mod_input_body_filter.c new file mode 100644 index 0000000..1a47341 --- /dev/null +++ b/debian/perl-framework/c-modules/input_body_filter/mod_input_body_filter.c @@ -0,0 +1,184 @@ +#define HTTPD_TEST_REQUIRE_APACHE 2 + +#if CONFIG_FOR_HTTPD_TEST + +<Location /input_body_filter> + SetHandler input-body-filter + InputBodyFilter On +</Location> + +#endif + +#include "httpd.h" +#include "http_config.h" +#include "http_protocol.h" +#include "http_request.h" +#include "http_log.h" +#include "ap_config.h" +#include "util_filter.h" +#include "apr_buckets.h" +#include "apr_strings.h" + +module AP_MODULE_DECLARE_DATA input_body_filter_module; + +#define INPUT_BODY_FILTER_NAME "INPUT_BODY_FILTER" + +typedef struct { + int enabled; +} input_body_filter_dcfg_t; + +static void *input_body_filter_dcfg_create(apr_pool_t *p, char *dummy) +{ + input_body_filter_dcfg_t *dcfg = + (input_body_filter_dcfg_t *)apr_pcalloc(p, sizeof(*dcfg)); + + return dcfg; +} + +static int input_body_filter_fixup_handler(request_rec *r) +{ + if ((r->method_number == M_POST) && r->handler && + !strcmp(r->handler, "input-body-filter")) + { + r->handler = "echo_post"; + } + + return OK; +} + +static int input_body_filter_response_handler(request_rec *r) +{ + if (strcmp(r->handler, "echo_post")) { + return DECLINED; + } + + if (r->method_number != M_POST) { + ap_rputs("1..1\nok 1\n", r); + return OK; + } + else { + return DECLINED; + } +} + +static void reverse_string(char *string, int len) +{ + register char *up, *down; + register unsigned char tmp; + + up = string; + down = string + len - 1; + + while (down > up) { + tmp = *up; + *up++ = *down; + *down-- = tmp; + } +} + +typedef struct input_body_ctx_t { + apr_bucket_brigade *b; +} input_body_ctx_t; + +static int input_body_filter_handler(ap_filter_t *f, apr_bucket_brigade *bb, + ap_input_mode_t mode, + apr_read_type_e block, + apr_off_t readbytes) +{ + request_rec *r = f->r; + conn_rec *c = r->connection; + apr_status_t rv; + input_body_ctx_t *ctx = f->ctx; + + if (!ctx) { + f->ctx = ctx = apr_pcalloc(r->pool, sizeof(*ctx)); + ctx->b = apr_brigade_create(r->pool, c->bucket_alloc); + } + + if (APR_BRIGADE_EMPTY(ctx->b)) + { + if ((rv = ap_get_brigade(f->next, ctx->b, mode, block, + readbytes)) != APR_SUCCESS) { + return rv; + } + } + + while (!APR_BRIGADE_EMPTY(ctx->b)) { + const char *data; + apr_size_t len; + apr_bucket *bucket; + + bucket = APR_BRIGADE_FIRST(ctx->b); + + if (APR_BUCKET_IS_EOS(bucket)) { + APR_BUCKET_REMOVE(bucket); + APR_BRIGADE_INSERT_TAIL(bb, bucket); + break; + } + + rv = apr_bucket_read(bucket, &data, &len, block); + + if (rv != APR_SUCCESS) { + return rv; + } + + APR_BUCKET_REMOVE(bucket); + + if (len) { + char *reversed = apr_pstrndup(r->pool, data, len); + reverse_string(reversed, len); + bucket = apr_bucket_pool_create(reversed, len, r->pool, + c->bucket_alloc); + } + + APR_BRIGADE_INSERT_TAIL(bb, bucket); + } + + return OK; +} + +static void input_body_filter_insert_filter(request_rec *r) +{ + input_body_filter_dcfg_t *dcfg = + ap_get_module_config(r->per_dir_config, + &input_body_filter_module); + + if (dcfg->enabled) { + ap_add_input_filter(INPUT_BODY_FILTER_NAME, NULL, r, r->connection); + } +} + +static void input_body_filter_register_hooks(apr_pool_t *p) +{ + ap_hook_fixups(input_body_filter_fixup_handler, + NULL, NULL, APR_HOOK_MIDDLE); + + ap_hook_handler(input_body_filter_response_handler, + NULL, NULL, APR_HOOK_MIDDLE); + + ap_hook_insert_filter(input_body_filter_insert_filter, + NULL, NULL, APR_HOOK_MIDDLE); + + ap_register_input_filter(INPUT_BODY_FILTER_NAME, + input_body_filter_handler, + NULL, + AP_FTYPE_RESOURCE); +} + +static const command_rec input_body_filter_cmds[] = { + AP_INIT_FLAG("InputBodyFilter", ap_set_flag_slot, + (void *)APR_OFFSETOF(input_body_filter_dcfg_t, enabled), + OR_ALL, "Enable input body filter"), + { NULL } +}; + +module AP_MODULE_DECLARE_DATA input_body_filter_module = { + STANDARD20_MODULE_STUFF, + input_body_filter_dcfg_create, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + input_body_filter_cmds, /* table of config file commands */ + input_body_filter_register_hooks /* register hooks */ +}; + diff --git a/debian/perl-framework/c-modules/list_modules/mod_list_modules.c b/debian/perl-framework/c-modules/list_modules/mod_list_modules.c new file mode 100644 index 0000000..40738a1 --- /dev/null +++ b/debian/perl-framework/c-modules/list_modules/mod_list_modules.c @@ -0,0 +1,38 @@ +#if CONFIG_FOR_HTTPD_TEST + +<Location /list_modules> + SetHandler list_modules +</Location> + +#endif + +#define APACHE_HTTPD_TEST_HANDLER list_modules_handler + +#define CORE_PRIVATE /* for ap_top_module */ +#include "apache_httpd_test.h" + +static int list_modules_handler(request_rec *r) +{ + module *modp; + + if (strcmp(r->handler, "list_modules")) { + return DECLINED; + } + if (r->method_number != M_GET) { + return DECLINED; + } + +#ifdef APACHE1 +#define ap_top_module top_module + ap_send_http_header(r); +#endif + + for (modp = ap_top_module; modp; modp = modp->next) { + ap_rvputs(r, modp->name, "\n", NULL); + } + + return OK; +} + +APACHE_HTTPD_TEST_MODULE(list_modules); + diff --git a/debian/perl-framework/c-modules/memory_track/mod_memory_track.c b/debian/perl-framework/c-modules/memory_track/mod_memory_track.c new file mode 100644 index 0000000..25d11ca --- /dev/null +++ b/debian/perl-framework/c-modules/memory_track/mod_memory_track.c @@ -0,0 +1,45 @@ +#if CONFIG_FOR_HTTPD_TEST + +<Location /memory_track> + SetHandler memory-track +</Location> + +#endif + +#define APACHE_HTTPD_TEST_HANDLER memory_track_handler + +#include "apache_httpd_test.h" +#include "ap_mpm.h" + +static int memory_track_handler(request_rec *r) +{ + int result; + + if (strcmp(r->handler, "memory-track")) { + return DECLINED; + } + if (r->method_number != M_GET) { + return DECLINED; + } + + /* t/apache/leaks.t not reliable with event. */ + if (!ap_mpm_query(AP_MPMQ_IS_ASYNC, &result) && result) { + return HTTP_SERVICE_UNAVAILABLE; + } + +#if APR_POOL_DEBUG + { + conn_rec *c = r->connection; + apr_size_t n = apr_pool_num_bytes(c->pool, 1); + + ap_rprintf(r, "connection,%ld,%lu\n", c->id, n); + } + + return OK; +#else + return HTTP_NOT_IMPLEMENTED; +#endif +} + +APACHE_HTTPD_TEST_MODULE(memory_track); + diff --git a/debian/perl-framework/c-modules/nntp_like/mod_nntp_like.c b/debian/perl-framework/c-modules/nntp_like/mod_nntp_like.c new file mode 100644 index 0000000..0fad8ce --- /dev/null +++ b/debian/perl-framework/c-modules/nntp_like/mod_nntp_like.c @@ -0,0 +1,181 @@ +#define HTTPD_TEST_REQUIRE_APACHE 2 + +/* + * purpose of this module is to test protocol modules that need to + * send data to the client before reading any request data. + * in this case, mod_ssl needs to handshake before sending data to the client. + * t/protocol/nntp-like.t tests both with and without ssl + * to make sure the protocol code works in both cases. + */ + +#if CONFIG_FOR_HTTPD_TEST + +<VirtualHost mod_nntp_like> + NNTPLike On +</VirtualHost> + +<IfModule @ssl_module@> + <VirtualHost mod_nntp_like_ssl> + NNTPLike On + SSLEngine On + </VirtualHost> +</IfModule> + +#endif + +#include "httpd.h" +#include "http_config.h" +#include "http_protocol.h" +#include "http_connection.h" +#include "http_request.h" +#include "http_log.h" +#include "ap_config.h" +#include "util_filter.h" +#include "apr_buckets.h" +#include "apr_strings.h" + +module AP_MODULE_DECLARE_DATA nntp_like_module; + +typedef struct { + int enabled; +} nntp_like_srv_cfg_t; + +static void *nntp_like_srv_cfg_create(apr_pool_t *p, server_rec *s) +{ + nntp_like_srv_cfg_t *cfg = apr_palloc(p, sizeof(*cfg)); + + cfg->enabled = 0; + + return cfg; +} + +static const char *nntp_like_cmd_enable(cmd_parms *cmd, void *dummy, int arg) +{ + nntp_like_srv_cfg_t *cfg = + ap_get_module_config(cmd->server->module_config, + &nntp_like_module); + cfg->enabled = arg; + + return NULL; +} + +/* this function just triggers the SSL handshake. + * normally that would happen in a protocol such as HTTP when + * the client request is read. however, with certain protocols + * such as NNTP, the server sends a response before the client + * sends a request + * + * if SSL is not enabled, this function is a noop + */ +static apr_status_t nntp_like_init_connection(conn_rec *c) +{ + apr_bucket_brigade *bb; + apr_status_t rv; + + bb = apr_brigade_create(c->pool, c->bucket_alloc); + + rv = ap_get_brigade(c->input_filters, bb, AP_MODE_INIT, + APR_BLOCK_READ, 0); + + apr_brigade_destroy(bb); + + return rv; +} + +static apr_status_t nntp_like_send_welcome(conn_rec *c) +{ + apr_bucket *bucket; + apr_bucket_brigade *bb = apr_brigade_create(c->pool, c->bucket_alloc); + +#define NNTP_LIKE_WELCOME \ + "200 localhost - ready\r\n" + + bucket = apr_bucket_immortal_create(NNTP_LIKE_WELCOME, + sizeof(NNTP_LIKE_WELCOME)-1, + c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, bucket); + APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_flush_create(c->bucket_alloc)); + + return ap_pass_brigade(c->output_filters, bb); +} + +static int nntp_like_pre_connection(conn_rec *c, void *csd) +{ + nntp_like_srv_cfg_t *cfg = + ap_get_module_config(c->base_server->module_config, + &nntp_like_module); + + if (cfg->enabled) { + apr_socket_timeout_set(csd, c->base_server->keep_alive_timeout); + } + + return DECLINED; +} + +static int nntp_like_process_connection(conn_rec *c) +{ + apr_bucket_brigade *bb; + apr_status_t rv; + nntp_like_srv_cfg_t *cfg = + ap_get_module_config(c->base_server->module_config, + &nntp_like_module); + + if (!cfg->enabled) { + return DECLINED; + } + + /* handshake if talking over SSL */ + if ((rv = nntp_like_init_connection(c)) != APR_SUCCESS) { + return rv; + } + + /* send the welcome message */ + if ((rv = nntp_like_send_welcome(c)) != APR_SUCCESS) { + return rv; + } + + do { + bb = apr_brigade_create(c->pool, c->bucket_alloc); + + if ((rv = ap_get_brigade(c->input_filters, bb, + AP_MODE_GETLINE, + APR_BLOCK_READ, 0)) != APR_SUCCESS || + APR_BRIGADE_EMPTY(bb)) + { + apr_brigade_destroy(bb); + break; + } + + APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_flush_create(c->bucket_alloc)); + + rv = ap_pass_brigade(c->output_filters, bb); + } while (rv == APR_SUCCESS); + + return OK; +} + +static void nntp_like_register_hooks(apr_pool_t *p) +{ + ap_hook_pre_connection(nntp_like_pre_connection, NULL, NULL, + APR_HOOK_MIDDLE); + ap_hook_process_connection(nntp_like_process_connection, + NULL, NULL, + APR_HOOK_MIDDLE); +} + +static const command_rec nntp_like_cmds[] = +{ + AP_INIT_FLAG("NNTPLike", nntp_like_cmd_enable, NULL, RSRC_CONF, + "enable nntp like protocol on this host"), + { NULL } +}; + +module AP_MODULE_DECLARE_DATA nntp_like_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + nntp_like_srv_cfg_create, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + nntp_like_cmds, /* table of config file commands */ + nntp_like_register_hooks /* register hooks */ +}; diff --git a/debian/perl-framework/c-modules/random_chunk/mod_random_chunk.c b/debian/perl-framework/c-modules/random_chunk/mod_random_chunk.c new file mode 100644 index 0000000..01da3e0 --- /dev/null +++ b/debian/perl-framework/c-modules/random_chunk/mod_random_chunk.c @@ -0,0 +1,182 @@ +#if CONFIG_FOR_HTTPD_TEST + +<Location /random_chunk> + SetHandler random_chunk +</Location> + +#endif + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2004 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + +/* + * This module is intended to be used for testing chunked encoding. It + * generates a whole whack of output using ap_bputc() and ap_bputs(). It + * also exercises start_chunk() and end_chunk() in buff.c. To use it + * you should use a tool like netcat and the src/test/check_chunked + * tool. Add something like this to your access.conf file: + * + * <Location /rndchunk> + * SetHandler rndchunk + * </Location> + * + * Then fake requests such as: + * + * GET /rndchunk?0,1000000 HTTP/1.1 + * Host: localhost + * + * The first arg is the random seed, the second is the number of + * "things" to do. You should try a few seeds. + * + * You should also edit main/buff.c and change DEFAULT_BUFSIZE (and + * CHUNK_HEADER_SIZE). Small values are particularly useful for + * finding bugs. Try a few different values. + * + * -djg + */ + +#define APACHE_HTTPD_TEST_HANDLER random_chunk_handler + +#include "apache_httpd_test.h" + +#define MAX_SEGMENT 32 +#define ONE_WEIGHT (256-32) + +#define WANT_HTTPD_TEST_SPLIT_QS_NUMBERS +#include "httpd_test_util.c" + +static int random_chunk_handler(request_rec *r) +{ + apr_size_t seed = 0; + apr_size_t count = 0; + int i; + char buf[MAX_SEGMENT + 1]; + unsigned int len; + apr_size_t total = 0; + + if (strcmp(r->handler, "random_chunk")) { + return DECLINED; + } + + if (r->proto_num < HTTP_VERSION(1,1)) { + return DECLINED; + } + + r->allowed |= (AP_METHOD_BIT << M_GET); + + if (r->method_number != M_GET) { + return DECLINED; + } + + r->content_type = "text/html"; + +#ifdef APACHE1 + ap_send_http_header(r); +#endif + if (r->header_only) { + return OK; + } + + httpd_test_split_qs_numbers(r, &seed, &count, NULL); + + if (!count) { + ap_rputs("Must include args! ... " + "of the form <code>?seed,count</code>", r); + return 0; + } + +#ifdef WIN32 + srand(seed); /* XXX: apr-ize */ +#else + srandom(seed); /* XXX: apr-ize */ +#endif + + for (i = 0; i < count; ++i) { +#ifdef WIN32 + len = rand() % (MAX_SEGMENT + ONE_WEIGHT); +#else + len = random() % (MAX_SEGMENT + ONE_WEIGHT); +#endif + + if (len >= MAX_SEGMENT) { + ap_rputc((i & 1) ? '0' : '1', r); + total += 1; + } + else if (len == 0) { + /* 1.x version used to do this; but chunk_filter does now */ +#if 0 + ap_bsetflag(r->connection->client, B_CHUNK, 0); + ap_bsetflag(r->connection->client, B_CHUNK, 1); +#endif + } + else { + memset(buf, '2' + len, len); + buf[len] = 0; + total += ap_rputs(buf, r); + } + } + + ap_rprintf(r, "__END__:%" APR_SIZE_T_FMT, total); + + fprintf(stderr, "[mod_random_chunk] sent %" APR_SIZE_T_FMT "bytes\n", + total); + + return 0; +} + +APACHE_HTTPD_TEST_MODULE(random_chunk); diff --git a/debian/perl-framework/c-modules/test_apr_uri/mod_test_apr_uri.c b/debian/perl-framework/c-modules/test_apr_uri/mod_test_apr_uri.c new file mode 100644 index 0000000..195e1ba --- /dev/null +++ b/debian/perl-framework/c-modules/test_apr_uri/mod_test_apr_uri.c @@ -0,0 +1,354 @@ +#define HTTPD_TEST_REQUIRE_APACHE 2 + +#if CONFIG_FOR_HTTPD_TEST + +<Location /test_apr_uri> + SetHandler test-apr-uri +</Location> + +#endif + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2004 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + * Portions of this software are based upon public domain software + * originally written at the National Center for Supercomputing Applications, + * University of Illinois, Urbana-Champaign. + */ + +/* + * This module is intended to test the apr_uri routines by parsing a + * bunch of urls and comparing the results with what we expect to + * see. + * + * Usage: + * + * <Location /test-apr-uri> + * SetHandler test-apr-uri + * </Location> + * + * Then make a request to /test-apr-uri. An html apr_table_t of errors will + * be output... and a total count of errors. + */ + +#include "httpd.h" +#include "http_protocol.h" +#include "http_config.h" +#include "http_main.h" + +typedef struct { + const char *scheme; + const char *user; + const char *password; + const char *hostname; + const char *port_str; + const char *path; + const char *query; + const char *fragment; +} test_uri_t; + +#define T_scheme 0x01 +#define T_user 0x02 +#define T_password 0x04 +#define T_hostname 0x08 +#define T_port_str 0x10 +#define T_path 0x20 +#define T_query 0x40 +#define T_fragment 0x80 +#define T_MAX 0x100 + +/* The idea is that we list here a bunch of url pieces that we want + * stitched together in every way that's valid. + */ +static const test_uri_t uri_tests[] = { + { "http", "userid", "passwd", "hostname.goes.here", "80", "/path/goes/here", "query-here", "frag-here" }, + { "http", "", "passwd", "hostname.goes.here", "80", "/path/goes/here", "query-here", "frag-here" }, + { "http", "userid", "", "hostname.goes.here", "80", "/path/goes/here", "query-here", "frag-here" }, + { "http", "userid", "passwd", "", "80", "/path/goes/here", "query-here", "frag-here" }, + { "http", "userid", "passwd", "hostname.goes.here", "", "/path/goes/here", "query-here", "frag-here" }, +#if 0 + /* An empty path means two different things depending on whether this is a + * relative or an absolute uri... consider <a href="#frag"> versus "GET + * http://hostname HTTP/1.1". So this is why parse_uri_components returns + * a NULL for path when it doesn't find one, instead of returning an empty + * string. + * + * We don't really need to test it explicitly since path has no explicit + * character that indicates its presence, and so we test empty paths all + * the time by varying T_path in the loop. It would just cost us extra + * code to special case the empty path string... + */ + { "http", "userid", "passwd", "hostname.goes.here", "80", "", "query-here", "frag-here" }, +#endif + { "http", "userid", "passwd", "hostname.goes.here", "80", "/path/goes/here", "", "frag-here" }, + { "http", "userid", "passwd", "hostname.goes.here", "80", "/path/goes/here", "query-here", "" }, + { "https", "user@d", "pa:swd", "hostname.goes.here.", "", "/~path/goes/here", "query&query?crud", "frag-here?baby" } + +}; + +static char *my_stpcpy(char *d, const char *s) +{ + while((*d = *s)) { + ++d; + ++s; + } + return d; +} + +/* return the number of failures */ +static unsigned iterate_pieces(request_rec *r, const test_uri_t *pieces, int row) +{ + unsigned u; + apr_pool_t *sub; + char *input_uri; + char *strp; + apr_uri_t result; + unsigned expect; + int status; + unsigned failures; + + failures = 0; + + input_uri = apr_palloc(r->pool, + strlen(pieces->scheme) + 3 + + strlen(pieces->user) + 1 + + strlen(pieces->password) + 1 + + strlen(pieces->hostname) + 1 + + strlen(pieces->port_str) + 1 + + strlen(pieces->path) + + + strlen(pieces->query) + 1 + + strlen(pieces->fragment) + 1 + + 1); + + for (u = 0; u < T_MAX; ++u) { + strp = input_uri; + expect = 0; + + /* a scheme requires a hostinfo and vice versa */ + /* a hostinfo requires a hostname */ + if (u & (T_scheme|T_user|T_password|T_hostname|T_port_str)) { + expect |= T_scheme; + strp = my_stpcpy(strp, pieces->scheme); + *strp++ = ':'; + *strp++ = '/'; + *strp++ = '/'; + /* can't have password without user */ + if (u & (T_user|T_password)) { + expect |= T_user; + strp = my_stpcpy(strp, pieces->user); + if (u & T_password) { + expect |= T_password; + *strp++ = ':'; + strp = my_stpcpy(strp, pieces->password); + } + *strp++ = '@'; + } + expect |= T_hostname; + strp = my_stpcpy(strp, pieces->hostname); + if (u & T_port_str) { + expect |= T_port_str; + *strp++ = ':'; + strp = my_stpcpy(strp, pieces->port_str); + } + } + if (u & T_path) { + expect |= T_path; + strp = my_stpcpy(strp, pieces->path); + } + if (u & T_query) { + expect |= T_query; + *strp++ = '?'; + strp = my_stpcpy(strp, pieces->query); + } + if (u & T_fragment) { + expect |= T_fragment; + *strp++ = '#'; + strp = my_stpcpy(strp, pieces->fragment); + } + *strp = 0; + + apr_pool_create_ex(&sub, r->pool, NULL, NULL); + status = apr_uri_parse(sub, input_uri, &result); + if (status == APR_SUCCESS) { +#define CHECK(f) \ + if ((expect & T_##f) \ + && (result.f == NULL || strcmp(result.f, pieces->f))) { \ + status = HTTP_INTERNAL_SERVER_ERROR; \ + } \ + else if (!(expect & T_##f) && result.f != NULL) { \ + status = HTTP_INTERNAL_SERVER_ERROR; \ + } + CHECK(scheme) + CHECK(user) + CHECK(password) + CHECK(hostname) + CHECK(port_str) + CHECK(path) + CHECK(query) + CHECK(fragment) +#undef CHECK + } + if (status != APR_SUCCESS) { + ap_rprintf(r, "<tr><td>%d</td><td>0x%02x</td><td>0x%02x</td><td>%d</td><td>\"%s\"</td>", row, u, expect, status, input_uri); +#define DUMP(f) \ + if (result.f) { \ + ap_rvputs(r, "<td>\"", result.f, "\"<br>", NULL); \ + } \ + else { \ + ap_rputs("<td>NULL<br>", r); \ + } \ + if (expect & T_##f) { \ + ap_rvputs(r, "\"", pieces->f, "\"</td>", NULL); \ + } \ + else { \ + ap_rputs("NULL</td>", r); \ + } + DUMP(scheme); + DUMP(user); + DUMP(password); + DUMP(hostname); + DUMP(port_str); + DUMP(path); + DUMP(query); + DUMP(fragment); +#undef DUMP + ap_rputs("</tr>\n", r); + ++failures; + } + apr_pool_destroy(sub); + } + return failures; +} + +static int test_apr_uri_handler(request_rec *r) +{ + unsigned total_failures; + int i; + + r->allowed |= (AP_METHOD_BIT << M_GET); + if (r->method_number != M_GET) + return DECLINED; + + if (strcmp(r->handler, "test-apr-uri")) { + return DECLINED; + } + + r->content_type = "text/html"; + + ap_rputs( +DOCTYPE_HTML_2_0 "\n\ +<html><body>\n\ +<p>Key:\n\ +<dl>\n\ +<dt>row\n\ +<dd>entry number in the uri_tests array\n\ +<dt>u\n\ +<dd>fields under test\n\ +<dt>expected\n\ +<dd>fields expected in the result\n\ +<dt>status\n\ +<dd>response from parse_uri_components, or 500 if unexpected results\n\ +<dt>input uri\n\ +<dd>the uri given to parse_uri_components\n\ +</dl>\n\ +<p>The remaining fields are the pieces returned from parse_uri_components, and\n\ +the values we expected for each piece (resp.).\n\ +<p>Only failures are displayed.\n\ +<p>\n\ +<table><tr><th>row</th><th>u</th><th>expect</th><th>status</th><th>input uri</th>", r); +#define HEADER(f) ap_rprintf(r, "<th>" #f "<br>0x%02x</th>", T_##f) + HEADER(scheme); + HEADER(user); + HEADER(password); + HEADER(hostname); + HEADER(port_str); + HEADER(path); + HEADER(query); + HEADER(fragment); +#undef HEADER + + if (r->args) { + i = atoi(r->args); + total_failures = iterate_pieces(r, &uri_tests[i], i); + } + else { + total_failures = 0; + for (i = 0; i < sizeof(uri_tests) / sizeof(uri_tests[0]); ++i) { + total_failures += iterate_pieces(r, &uri_tests[i], i); + if (total_failures > 256) { + ap_rprintf(r, "</table>\n<b>Stopped early to save your browser " + "from certain death!</b>\nTOTAL FAILURES = %u\n", + total_failures); + return OK; + } + } + } + ap_rprintf(r, "</table>\nTOTAL FAILURES = %u\n", total_failures); + + return OK; +} + +static void test_apr_uri_register_hooks(apr_pool_t *p) +{ + ap_hook_handler(test_apr_uri_handler, NULL, NULL, APR_HOOK_MIDDLE); +} + +module AP_MODULE_DECLARE_DATA test_apr_uri_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + NULL, /* table of config file commands */ + test_apr_uri_register_hooks /* register hooks */ +}; diff --git a/debian/perl-framework/c-modules/test_pass_brigade/mod_test_pass_brigade.c b/debian/perl-framework/c-modules/test_pass_brigade/mod_test_pass_brigade.c new file mode 100644 index 0000000..99bc95a --- /dev/null +++ b/debian/perl-framework/c-modules/test_pass_brigade/mod_test_pass_brigade.c @@ -0,0 +1,104 @@ +#define HTTPD_TEST_REQUIRE_APACHE 2 + +#if CONFIG_FOR_HTTPD_TEST + +<Location /test_pass_brigade> + SetHandler test_pass_brigade +</Location> + +#endif + +#define APACHE_HTTPD_TEST_HANDLER test_pass_brigade_handler + +#include "apache_httpd_test.h" + +#include "apr_buckets.h" + +#define WANT_HTTPD_TEST_SPLIT_QS_NUMBERS +#include "httpd_test_util.c" + +/* + * mainly for testing / researching core_output_filter buffering + */ + +static int test_pass_brigade_handler(request_rec *r) +{ + conn_rec *c = r->connection; + size_t total=0, remaining=1; + char *buff; + size_t buff_size = 8192; + apr_bucket_brigade *bb; + + if (strcmp(r->handler, "test_pass_brigade")) { + return DECLINED; + } + if (r->method_number != M_GET) { + return DECLINED; + } + + httpd_test_split_qs_numbers(r, &buff_size, &remaining, NULL); + + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + "going to echo %" APR_SIZE_T_FMT " bytes with " + "buffer size=%" APR_SIZE_T_FMT "", + remaining, buff_size); + + buff = malloc(buff_size); + memset(buff, 'a', buff_size); + bb = apr_brigade_create(r->pool, c->bucket_alloc); + + while (total < remaining) { + int left = (remaining - total); + int len = left <= buff_size ? left : buff_size; + apr_bucket *bucket = apr_bucket_transient_create(buff, len, + c->bucket_alloc); + apr_status_t status; + + apr_brigade_cleanup(bb); + APR_BRIGADE_INSERT_TAIL(bb, bucket); + if (len + total == remaining) { + bucket = apr_bucket_eos_create(c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, bucket); + +#if 0 + /* ###### A FLUSH should not be strictly necessary here + * but inserting one apears to work around intermittent + * failures when running t/apache/pass_brigade.t under + * worker. */ + bucket = apr_bucket_flush_create(c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, bucket); +#endif + + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + "[mod_test_pass_brigade] sending EOS"); + } + + status = ap_pass_brigade(r->output_filters->next, bb); + + if (status != APR_SUCCESS) { + apr_brigade_destroy(bb); + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, + "[mod_test_pass_brigade] ap_pass_brigade failed"); + free(buff); + return HTTP_INTERNAL_SERVER_ERROR; + } + + total += len; + + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "[mod_test_pass_brigade] wrote %d of %d bytes", + len, len); + } + + apr_brigade_destroy(bb); + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + "[mod_test_pass_brigade] done writing %" APR_SIZE_T_FMT + " of %" APR_SIZE_T_FMT " bytes", + total, remaining); + + free(buff); + return OK; +} + +APACHE_HTTPD_TEST_MODULE(test_pass_brigade); + diff --git a/debian/perl-framework/c-modules/test_rwrite/mod_test_rwrite.c b/debian/perl-framework/c-modules/test_rwrite/mod_test_rwrite.c new file mode 100644 index 0000000..64f1542 --- /dev/null +++ b/debian/perl-framework/c-modules/test_rwrite/mod_test_rwrite.c @@ -0,0 +1,66 @@ +#if CONFIG_FOR_HTTPD_TEST + +<Location /test_rwrite> + SetHandler test_rwrite +</Location> + +#endif + +#define APACHE_HTTPD_TEST_HANDLER test_rwrite_handler + +#include "apache_httpd_test.h" + +#define WANT_HTTPD_TEST_SPLIT_QS_NUMBERS +#include "httpd_test_util.c" + +static int test_rwrite_handler(request_rec *r) +{ + size_t total=0, remaining=1; + char *buff; + size_t buff_size = 8192; + + if (strcmp(r->handler, "test_rwrite")) { + return DECLINED; + } + if (r->method_number != M_GET) { + return DECLINED; + } + + if (r->args) { + remaining = atol(r->args); + } + +#ifdef APACHE1 + ap_send_http_header(r); +#endif + + httpd_test_split_qs_numbers(r, &buff_size, &remaining, NULL); + + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + "[mod_test_rwrite] going to echo %" APR_SIZE_T_FMT " bytes", + remaining); + + buff = malloc(buff_size); + memset(buff, 'a', buff_size); + + while (total < remaining) { + int left = (remaining - total); + int len = left <= buff_size ? left : buff_size; + long nrd = ap_rwrite(buff, len, r); + total += nrd; + + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "[mod_test_rwrite] wrote %ld of %d bytes", nrd, len); + } + + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + "[mod_test_rwrite] done writing %" APR_SIZE_T_FMT + " of %" APR_SIZE_T_FMT " bytes", + total, remaining); + + free(buff); + return OK; +} + +APACHE_HTTPD_TEST_MODULE(test_rwrite); + diff --git a/debian/perl-framework/c-modules/test_session/mod_test_session.c b/debian/perl-framework/c-modules/test_session/mod_test_session.c new file mode 100644 index 0000000..4099cbe --- /dev/null +++ b/debian/perl-framework/c-modules/test_session/mod_test_session.c @@ -0,0 +1,348 @@ +#define HTTPD_TEST_REQUIRE_APACHE 2.3 + +#if CONFIG_FOR_HTTPD_TEST + +<IfModule mod_session.c> + <Location /sessiontest> + Session Off + TestSession On + SetHandler test-session-handler + </Location> + <Location /sessiontest/on> + Session On + SessionHeader X-Test-Session-Override + </Location> + <Location /sessiontest/on/encode> + TestSessionEncoder On + </Location> + <IfModule mod_include.c> + Alias /sessiontest/on/env/on @DocumentRoot@/modules/session + <Directory @DocumentRoot@/modules/session> + Session On + SessionEnv Off + TestSession On + Options +IncludesNOEXEC + </Directory> + <Location /sessiontest/on/env> + SetHandler None + </Location> + <Location /sessiontest/on/env/on> + SessionEnv On + </Location> + </IfModule> + <Location /sessiontest/on/expire> + SessionMaxAge 100 + </Location> + <IfModule mod_version.c> + <IfVersion >= 2.4.41> + <Location /sessiontest/on/expire/cache> + SessionExpiryUpdateInterval 50 + </Location> + </IfVersion> + </IfModule> + <Location /sessiontest/on/include> + SessionInclude /sessiontest/on/include/yes + SessionExclude /sessiontest/on/include/yes/no + </Location> +</IfModule> + +#endif + +#include "apr_strings.h" +#include "mod_session.h" + +#define APACHE_HTTPD_TEST_EXTRA_HOOKS extra_hooks +#define APACHE_HTTPD_TEST_CHILD_INIT test_session_init +#define APACHE_HTTPD_TEST_HANDLER test_session_handler +#define APACHE_HTTPD_TEST_COMMANDS test_session_cmds +#define APACHE_HTTPD_TEST_PER_DIR_CREATE test_session_dcfg_create +#define APACHE_HTTPD_TEST_PER_DIR_MERGE test_session_dcfg_merge + +#include "apache_httpd_test.h" + +#define TEST_SESSION_HANDLER "test-session-handler" +#define TEST_SESSION_ENCODER "test-session-encoder" +#define TEST_SESSION_NOTE "mod_test_session" +#define TEST_SESSION_HEADER "X-Test-Session-Override" +#define TEST_SESSION_ENCODING_PREFIX "TestEncoded:" + +typedef struct { + int session; + int session_set; + int encoder; + int encoder_set; +} test_session_dcfg_t; + +typedef enum { + TEST_SESSION_ACTION_NONE, + TEST_SESSION_ACTION_GET, + TEST_SESSION_ACTION_SET +} TestSessionAction; + +module AP_MODULE_DECLARE_DATA test_session_module; + +static APR_OPTIONAL_FN_TYPE(ap_session_get) *ap_session_get_fn = NULL; +static APR_OPTIONAL_FN_TYPE(ap_session_set) *ap_session_set_fn = NULL; +static APR_OPTIONAL_FN_TYPE(ap_session_load) *ap_session_load_fn = NULL; +static APR_OPTIONAL_FN_TYPE(ap_session_save) *ap_session_save_fn = NULL; + +static void test_session_init(apr_pool_t *p, server_rec *s) +{ + ap_session_get_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_get); + ap_session_set_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_set); + ap_session_save_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_save); + ap_session_load_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_load); +} + +static apr_status_t test_session_load(request_rec * r, session_rec ** z) +{ + session_rec *zz; + test_session_dcfg_t *dconf = ap_get_module_config(r->per_dir_config, + &test_session_module); + if (!dconf || !dconf->session) + return DECLINED; + + zz = (session_rec *)apr_table_get(r->notes, TEST_SESSION_NOTE); + + if (!zz) { + /* Create the session using the query string as the data. */ + char *data = apr_pstrdup(r->pool, r->args); + + if (data) { + int result = ap_unescape_urlencoded(data); + if (result) + return result; + } + + zz = (session_rec *)apr_pcalloc(r->pool, sizeof(session_rec)); + zz->pool = r->pool; + zz->entries = apr_table_make(r->pool, 10); + zz->encoded = data; + apr_table_setn(r->notes, TEST_SESSION_NOTE, (char *)zz); + } + + *z = zz; + return OK; +} + +static apr_status_t test_session_save(request_rec * r, session_rec * z) +{ + test_session_dcfg_t *dconf = ap_get_module_config(r->per_dir_config, + &test_session_module); + if (!dconf || !dconf->session) + return DECLINED; + + /* Save the session into headers. */ + apr_table_setn(r->headers_out, "X-Test-Session-Dirty", + z->dirty ? "1" : "0"); + + apr_table_set(r->headers_out, "X-Test-Session", z->encoded); + + return OK; +} + +static apr_status_t test_session_encode(request_rec * r, session_rec * z) +{ + test_session_dcfg_t *dconf = ap_get_module_config(r->per_dir_config, + &test_session_module); + if (!dconf || !dconf->encoder) + return DECLINED; + + /* Simple encoding by adding a prefix. */ + z->encoded = apr_pstrcat(r->pool, TEST_SESSION_ENCODING_PREFIX, + z->encoded, NULL); + return OK; +} + +static apr_status_t test_session_decode(request_rec * r, session_rec * z) +{ + const size_t prefix_len = strlen(TEST_SESSION_ENCODING_PREFIX); + test_session_dcfg_t *dconf = ap_get_module_config(r->per_dir_config, + &test_session_module); + if (!dconf || !dconf->encoder || !z->encoded) + return DECLINED; + + /* Simple decoding by removing a prefix. */ + if (!strncmp(z->encoded, TEST_SESSION_ENCODING_PREFIX, prefix_len)) { + z->encoded += prefix_len; + return OK; + } + + return HTTP_BAD_REQUEST; +} + +static int test_session_get(request_rec *r, char *name) +{ + session_rec *z = NULL; + const char *value = NULL; + apr_status_t result = ap_session_load_fn(r, &z); + + if (result == OK) + result = ap_session_get_fn(r, z, name, &value); + + if (result == OK) { + if (value) + result = ap_rputs(value, r) > 0 ? OK : HTTP_INTERNAL_SERVER_ERROR; + else + result = HTTP_NOT_FOUND; + } + + return result; +} + +static int test_session_set(request_rec *r, char *name, char *value) +{ + session_rec *z = NULL; + apr_status_t result = ap_session_load_fn(r, &z); + + if (result == OK) + result = ap_session_set_fn(r, z, name, value); + + return result; +} + +static int test_session_handler(request_rec *r) +{ + const char *overrides = NULL; + + if (strcmp(r->handler, TEST_SESSION_HANDLER)) + return DECLINED; + + /* Copy the header for SessionHeader from the request to the response. */ + if ((overrides = apr_table_get(r->headers_in, TEST_SESSION_HEADER))) + apr_table_setn(r->headers_out, TEST_SESSION_HEADER, overrides); + + /* Additional commands to test the session API via POST. */ + if (r->method_number == M_POST) { + char *fieldName = NULL; + char *fieldValue = NULL; + apr_array_header_t *pairs = NULL; + apr_status_t result; + TestSessionAction action; + + if (!ap_session_get_fn || !ap_session_set_fn || + !ap_session_load_fn || !ap_session_save_fn) + return HTTP_INTERNAL_SERVER_ERROR; + + action = TEST_SESSION_ACTION_NONE; + result = ap_parse_form_data(r, NULL, &pairs, 3, 1024); + + if (result != OK) + return result; + + while (pairs && !apr_is_empty_array(pairs)) { + ap_form_pair_t *pair = (ap_form_pair_t *)apr_array_pop(pairs); + if (!strcmp(pair->name, "action")) { + apr_size_t len; + char *value = NULL; + result = apr_brigade_pflatten(pair->value, &value, &len, + r->pool); + if (result == OK && !strncmp(value, "get", len)) + action = TEST_SESSION_ACTION_GET; + else if (result == OK && !strncmp(value, "set", len)) + action = TEST_SESSION_ACTION_SET; + else + return HTTP_BAD_REQUEST; + } + else if (!strcmp(pair->name, "name")) { + apr_off_t off; + apr_size_t len; + apr_brigade_length(pair->value, 1, &off); + len = (apr_size_t)off; + fieldName = apr_pcalloc(r->pool, sizeof(char) * len + 1); + result = apr_brigade_flatten(pair->value, fieldName, &len); + } + else if (!strcmp(pair->name, "value")) { + apr_off_t off; + apr_size_t len; + apr_brigade_length(pair->value, 1, &off); + len = (apr_size_t)off; + fieldValue = apr_pcalloc(r->pool, sizeof(char) * len + 1); + result = apr_brigade_flatten(pair->value, fieldValue, &len); + } + else { + return HTTP_BAD_REQUEST; + } + + if (result != OK) + return result; + } + + switch (action) { + case TEST_SESSION_ACTION_GET: + return test_session_get(r, fieldName); + + case TEST_SESSION_ACTION_SET: + return test_session_set(r, fieldName, fieldValue); + + default: + return HTTP_BAD_REQUEST; + } + } + + return OK; +} + +static void *test_session_dcfg_create(apr_pool_t *p, char *dummy) +{ + return apr_pcalloc(p, sizeof(test_session_dcfg_t)); +} + +static void *test_session_dcfg_merge(apr_pool_t * p, void *basev, void *addv) +{ + test_session_dcfg_t *add = addv; + test_session_dcfg_t *base = basev; + test_session_dcfg_t *new = apr_pcalloc(p, sizeof(test_session_dcfg_t)); + + new->session = (add->session_set == 0) ? base->session : add->session; + new->session_set = add->session_set || base->session_set; + new->encoder = (add->encoder_set == 0) ? base->encoder : add->encoder; + new->encoder_set = add->encoder_set || base->encoder_set; + + return new; +} + +static const char *set_session_enable(cmd_parms * parms, void *dconf, int flag) +{ + test_session_dcfg_t *conf = dconf; + + conf->session = flag; + conf->session_set = 1; + + return NULL; +} + +static const char *set_encoder_enable(cmd_parms * parms, void *dconf, int flag) +{ + test_session_dcfg_t *conf = dconf; + + conf->encoder = flag; + conf->encoder_set = 1; + + return NULL; +} + +static const command_rec test_session_cmds[] = { + AP_INIT_FLAG("TestSession", set_session_enable, NULL, OR_ALL, + "Enable test sessions"), + AP_INIT_FLAG("TestSessionEncoder", set_encoder_enable, NULL, OR_ALL, + "Enable test session encoding"), + { NULL } +}; + +static void extra_hooks(apr_pool_t *pool) +{ + ap_hook_session_load(test_session_load, + NULL, NULL, APR_HOOK_MIDDLE); + + ap_hook_session_save(test_session_save, + NULL, NULL, APR_HOOK_MIDDLE); + + ap_hook_session_encode(test_session_encode, + NULL, NULL, APR_HOOK_MIDDLE); + + ap_hook_session_decode(test_session_decode, + NULL, NULL, APR_HOOK_MIDDLE); +} + +APACHE_HTTPD_TEST_MODULE(test_session); diff --git a/debian/perl-framework/c-modules/test_ssl/mod_test_ssl.c b/debian/perl-framework/c-modules/test_ssl/mod_test_ssl.c new file mode 100644 index 0000000..c9bc762 --- /dev/null +++ b/debian/perl-framework/c-modules/test_ssl/mod_test_ssl.c @@ -0,0 +1,171 @@ +#define HTTPD_TEST_REQUIRE_APACHE 2 + +#if CONFIG_FOR_HTTPD_TEST + +<IfModule @ssl_module@> + <Location /test_ssl_var_lookup> + SetHandler test-ssl-var-lookup + SSLVerifyClient require + SSLVerifyDepth 10 + </Location> + + <Location /test_ssl_ext_lookup> + SetHandler test-ssl-ext-lookup + SSLVerifyClient require + SSLVerifyDepth 10 + </Location> +</IfModule> + +#endif + +#include "httpd.h" +#include "http_config.h" +#include "http_protocol.h" +#include "http_log.h" +#include "ap_config.h" +#include "apr_optional.h" + +#if AP_MODULE_MAGIC_AT_LEAST(20040425, 0) /* simply include mod_ssl.h if using >= 2.1.0 */ + +#include "mod_ssl.h" + +#if MODULE_MAGIC_COOKIE > 0x41503234UL || \ + (MODULE_MAGIC_COOKIE == 0x41503234UL \ + && AP_MODULE_MAGIC_AT_LEAST(20050919, 0)) /* ssl_ext_list() only in 2.4.x */ +#define HAVE_SSL_EXT_LIST +static APR_OPTIONAL_FN_TYPE(ssl_ext_list) *ext_list; +#elif AP_MODULE_MAGIC_AT_LEAST(20050127, 0) /* approx. when ssl_ext_lookup was added */ +#define HAVE_SSL_EXT_LOOKUP +static APR_OPTIONAL_FN_TYPE(ssl_ext_lookup) *ext_lookup; +#endif + +#else +/* For use of < 2.0.x, inline the declaration: */ + +APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup, + (apr_pool_t *, server_rec *, + conn_rec *, request_rec *, + char *)); + +#endif + +static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *var_lookup; + +static void import_ssl_var_lookup(void) +{ + var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); +#ifdef HAVE_SSL_EXT_LOOKUP + ext_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_ext_lookup); +#endif +#ifdef HAVE_SSL_EXT_LIST + ext_list = APR_RETRIEVE_OPTIONAL_FN(ssl_ext_list); +#endif +} + +#if defined(HAVE_SSL_EXT_LOOKUP) || defined(HAVE_SSL_EXT_LIST) +static int test_ssl_ext_lookup(request_rec *r) +{ + const char *value; + + if (strcmp(r->handler, "test-ssl-ext-lookup") + || r->method_number != M_GET) { + return DECLINED; + } + + if (!r->args) { + ap_rputs("no query", r); + return OK; + } + +#ifdef HAVE_SSL_EXT_LOOKUP + if (!ext_lookup) { + ap_rputs("ssl_ext_lookup not available", r); + return OK; + } + + value = ext_lookup(r->pool, r->connection, 1, r->args); +#else + if (!ext_list) { + ap_rputs("ssl_ext_list not available", r); + return OK; + } + + { + apr_array_header_t *vals = ext_list(r->pool, r->connection, 1, + r->args); + + if (vals) { + value = *(const char **)apr_array_pop(vals); + } + else { + value = NULL; + } + } +#endif + + if (!value) value = "NULL"; + + ap_rputs(value, r); + + return OK; +} + +#endif + +static int test_ssl_var_lookup(request_rec *r) +{ + const char *value; + + if (strcmp(r->handler, "test-ssl-var-lookup")) { + return DECLINED; + } + + if (r->method_number != M_GET) { + return DECLINED; + } + + if (!r->args) { + ap_rputs("no query", r); + return OK; + } + + apr_table_setn(r->subprocess_env, "THE_ARGS", r->args); + + if (!var_lookup) { + ap_rputs("ssl_var_lookup is not available", r); + return OK; + } + + value = var_lookup(r->pool, r->server, + r->connection, r, r->args); + + if (value && *value) { + ap_rputs(value, r); + } + else { + ap_rputs("NULL", r); + } + + return OK; +} + +static void test_ssl_register_hooks(apr_pool_t *p) +{ + ap_hook_handler(test_ssl_var_lookup, NULL, NULL, APR_HOOK_MIDDLE); +#if defined(HAVE_SSL_EXT_LOOKUP) || defined(HAVE_SSL_EXT_LIST) + ap_hook_handler(test_ssl_ext_lookup, NULL, NULL, APR_HOOK_MIDDLE); +#endif + ap_hook_optional_fn_retrieve(import_ssl_var_lookup, + NULL, NULL, APR_HOOK_MIDDLE); +} + +module AP_MODULE_DECLARE_DATA test_ssl_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + NULL, /* table of config file commands */ + test_ssl_register_hooks /* register hooks */ +}; + diff --git a/debian/perl-framework/c-modules/test_utilities/mod_test_utilities.c b/debian/perl-framework/c-modules/test_utilities/mod_test_utilities.c new file mode 100644 index 0000000..5236585 --- /dev/null +++ b/debian/perl-framework/c-modules/test_utilities/mod_test_utilities.c @@ -0,0 +1,48 @@ +#define HTTPD_TEST_REQUIRE_APACHE 2.4 + +/** + * This module provides utility functions for other tests; it doesn't provide + * test cases of its own. + */ + +#define APACHE_HTTPD_TEST_EXTRA_HOOKS util_register_hooks +#include "apache_httpd_test.h" + +#include "apr_strings.h" +#include "ap_expr.h" + +/** + * The util_strlen() ap_expr function simply returns the length of its string + * argument as a decimal string. + */ +static const char *util_strlen_func(ap_expr_eval_ctx_t *ctx, const void *data, + const char *arg) +{ + if (!arg) { + return NULL; + } + + return apr_psprintf(ctx->p, "%" APR_SIZE_T_FMT, strlen(arg)); +} + +static int util_expr_lookup(ap_expr_lookup_parms *parms) +{ + switch (parms->type) { + case AP_EXPR_FUNC_STRING: + if (!strcasecmp(parms->name, "util_strlen")) { + *parms->func = util_strlen_func; + *parms->data = "dummy"; + return OK; + } + break; + } + + return DECLINED; +} + +static void util_register_hooks(apr_pool_t *p) +{ + ap_hook_expr_lookup(util_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE); +} + +APACHE_HTTPD_TEST_MODULE(test_utilities); |