Author: jkaluza
Date: Wed Feb 20 11:40:50 2013
New Revision: 1448098

URL: http://svn.apache.org/r1448098
Log:
Add new authz/authn API defined in httpd-2.4. It adds new directives
PerlAddAuthzProvider/PerlAddAuthnProvider to register providers and
RequestUtil::register_auth_provider method.

This commit is initial try to port this new API to mod_perl and it definitely
needs a review.


Modified:
    perl/modperl/branches/httpd24/lib/Apache2/ParseSource.pm
    perl/modperl/branches/httpd24/lib/ModPerl/Code.pm
    perl/modperl/branches/httpd24/src/modules/perl/mod_perl.c
    perl/modperl/branches/httpd24/src/modules/perl/modperl_apache_includes.h
    perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.c
    perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.h
    perl/modperl/branches/httpd24/src/modules/perl/modperl_util.c
    perl/modperl/branches/httpd24/src/modules/perl/modperl_util.h
    perl/modperl/branches/httpd24/xs/Apache2/RequestUtil/Apache2__RequestUtil.h
    perl/modperl/branches/httpd24/xs/maps/apache2_functions.map

Modified: perl/modperl/branches/httpd24/lib/Apache2/ParseSource.pm
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/lib/Apache2/ParseSource.pm?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/lib/Apache2/ParseSource.pm (original)
+++ perl/modperl/branches/httpd24/lib/Apache2/ParseSource.pm Wed Feb 20 
11:40:50 2013
@@ -255,6 +255,7 @@ my %defines_wanted = (
         remotehost => [qw{REMOTE_}],
         satisfy    => [qw{SATISFY_}],
         types      => [qw{DIR_MAGIC_TYPE}],
+        auth       => [qw{AUTHN_ AUTHZ AP_AUTH_ AUTH_ AUTHZ_}],
     },
     'APR::Const' => {
         common    => [qw{APR_SUCCESS}],
@@ -287,7 +288,7 @@ while (my ($class, $groups) = each %defi
 }
 
 my %enums_wanted = (
-    'Apache2::Const' => { map { $_, 1 } qw(cmd_how input_mode filter_type 
conn_keepalive) },
+    'Apache2::Const' => { map { $_, 1 } qw(cmd_how input_mode filter_type 
conn_keepalive authn_status authz_status) },
     'APR::Const' => { map { $_, 1 } qw(apr_shutdown_how apr_read_type 
apr_lockmech) },
 );
 

Modified: perl/modperl/branches/httpd24/lib/ModPerl/Code.pm
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/lib/ModPerl/Code.pm?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/lib/ModPerl/Code.pm (original)
+++ perl/modperl/branches/httpd24/lib/ModPerl/Code.pm Wed Feb 20 11:40:50 2013
@@ -891,6 +891,15 @@ EOF
             if ($name eq 'DECLINE_CMD' ||
                 $name eq 'DIR_MAGIC_TYPE' ||
                 $name eq 'CRLF' ||
+                $name eq 'AUTHN_PROVIDER_GROUP' ||
+                $name eq 'AUTHZ_PROVIDER_GROUP' ||
+                $name eq 'AUTHN_PROVIDER_VERSION' ||
+                $name eq 'AUTHZ_PROVIDER_VERSION' ||
+                $name eq 'AUTHN_DEFAULT_PROVIDER' ||
+                $name eq 'AUTHN_PROVIDER_NAME_NOTE' ||
+                $name eq 'AUTHZ_PROVIDER_NAME_NOTE' ||
+                $name eq 'AUTHN_PREFIX' ||
+                $name eq 'AUTHZ_PREFIX' ||
                 $name eq 'CRLF_ASCII') {
                 print $c_fh <<EOF;
               return newSVpv($alias{$name}, 0);

Modified: perl/modperl/branches/httpd24/src/modules/perl/mod_perl.c
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/src/modules/perl/mod_perl.c?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/src/modules/perl/mod_perl.c (original)
+++ perl/modperl/branches/httpd24/src/modules/perl/mod_perl.c Wed Feb 20 
11:40:50 2013
@@ -911,6 +911,8 @@ static const command_rec modperl_cmds[] 
     MP_CMD_DIR_ITERATE("PerlRequire", requires, "PerlRequire"),
     MP_CMD_SRV_ITERATE("PerlConfigRequire", config_requires, 
"PerlConfigRequire"),
     MP_CMD_SRV_ITERATE("PerlPostConfigRequire", post_config_requires, 
"PerlPostConfigRequire"),
+    MP_CMD_SRV_TAKE2("PerlAddAuthzProvider", authz_provider, 
"PerlAddAuthzProvider"),
+    MP_CMD_SRV_TAKE2("PerlAddAuthnProvider", authn_provider, 
"PerlAddAuthnProvider"),
     MP_CMD_DIR_ITERATE("PerlOptions", options, "Perl Options"),
     MP_CMD_DIR_ITERATE("PerlInitHandler", init_handlers, "Subroutine name"),
     MP_CMD_DIR_TAKE2("PerlSetVar", set_var, "PerlSetVar"),

Modified: 
perl/modperl/branches/httpd24/src/modules/perl/modperl_apache_includes.h
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/src/modules/perl/modperl_apache_includes.h?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/src/modules/perl/modperl_apache_includes.h 
(original)
+++ perl/modperl/branches/httpd24/src/modules/perl/modperl_apache_includes.h 
Wed Feb 20 11:40:50 2013
@@ -43,4 +43,9 @@
 APLOG_USE_MODULE(perl);
 #endif
 
+#if AP_SERVER_MAJORVERSION_NUMBER>2 || \
+    (AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER>=3)
+#include "mod_auth.h"
+#endif
+
 #endif /* MODPERL_APACHE_INCLUDES_H */

Modified: perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.c
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.c?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.c (original)
+++ perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.c Wed Feb 20 
11:40:50 2013
@@ -417,6 +417,30 @@ MP_CMD_SRV_DECLARE(init_handlers)
     return modperl_cmd_post_read_request_handlers(parms, mconfig, arg);
 }
 
+MP_CMD_SRV_DECLARE2(authz_provider)
+{
+    apr_pool_t *p = parms->server->process->pool;
+    char *name = apr_pstrdup(p, arg1);
+    char *cb = apr_pstrdup(p, arg2);
+
+    modperl_register_auth_provider_name(p, AUTHZ_PROVIDER_GROUP, name,
+                                        AUTHZ_PROVIDER_VERSION, cb, NULL,
+                                        AP_AUTH_INTERNAL_PER_CONF);
+    return NULL;
+}
+
+MP_CMD_SRV_DECLARE2(authn_provider)
+{
+    apr_pool_t *p = parms->server->process->pool;
+    char *name = apr_pstrdup(p, arg1);
+    char *cb = apr_pstrdup(p, arg2);
+
+    modperl_register_auth_provider_name(p, AUTHN_PROVIDER_GROUP, name,
+                                        AUTHN_PROVIDER_VERSION, cb, NULL,
+                                        AP_AUTH_INTERNAL_PER_CONF);
+    return NULL;
+}
+
 static const char *modperl_cmd_parse_args(apr_pool_t *p,
                                           const char *args,
                                           apr_table_t **t)

Modified: perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.h
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.h?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.h (original)
+++ perl/modperl/branches/httpd24/src/modules/perl/modperl_cmd.h Wed Feb 20 
11:40:50 2013
@@ -42,6 +42,8 @@ MP_CMD_SRV_DECLARE(modules);
 MP_CMD_SRV_DECLARE(requires);
 MP_CMD_SRV_DECLARE(config_requires);
 MP_CMD_SRV_DECLARE(post_config_requires);
+MP_CMD_SRV_DECLARE2(authz_provider);
+MP_CMD_SRV_DECLARE2(authn_provider);
 MP_CMD_SRV_DECLARE2(set_var);
 MP_CMD_SRV_DECLARE2(add_var);
 MP_CMD_SRV_DECLARE2(set_env);

Modified: perl/modperl/branches/httpd24/src/modules/perl/modperl_util.c
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/src/modules/perl/modperl_util.c?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/src/modules/perl/modperl_util.c (original)
+++ perl/modperl/branches/httpd24/src/modules/perl/modperl_util.c Wed Feb 20 
11:40:50 2013
@@ -910,3 +910,306 @@ U16 *modperl_code_attrs(pTHX_ CV *cv) {
     mg = mg_find((SV*)cv, PERL_MAGIC_ext);
     return &(mg->mg_private);
 }
+
+static apr_hash_t *global_authz_providers = NULL;
+static apr_hash_t *global_authn_providers = NULL;
+
+typedef struct {
+    SV *cb1;
+    SV *cb2;
+    modperl_handler_t *cb1_handler;
+    modperl_handler_t *cb2_handler;
+} auth_callback;
+
+static apr_status_t cleanup_perl_global_providers(void *ctx)
+{
+    global_authz_providers = NULL;
+    global_authn_providers = NULL;
+    return APR_SUCCESS;
+}
+
+static authz_status perl_check_authorization(request_rec *r,
+                                             const char *require_args,
+                                             const void *parsed_require_args)
+{
+    authz_status ret = AUTHZ_DENIED;
+    int count;
+    AV *args = Nullav;
+
+    if (global_authz_providers == NULL) {
+        return ret;
+    }
+
+    const char *key = apr_table_get(r->notes, AUTHZ_PROVIDER_NAME_NOTE);
+    auth_callback *ab = apr_hash_get(global_authz_providers, key,
+                                     APR_HASH_KEY_STRING);
+    if (ab == NULL) {
+        return ret;
+    }
+
+    MP_dTHX;
+
+    if (ab->cb1 == NULL) {
+        if (ab->cb1_handler == NULL) {
+            return ret;
+        }
+
+        modperl_handler_make_args(aTHX_ &args, "Apache2::RequestRec", r,
+                                  "PV", require_args, NULL);
+        ret = modperl_callback(aTHX_ ab->cb1_handler, r->pool, r, r->server,
+                               args);
+        SvREFCNT_dec((SV*)args);
+        return ret;
+    }
+
+    dSP;
+    ENTER;
+    SAVETMPS;
+    PUSHMARK(SP);
+    XPUSHs(sv_2mortal(modperl_ptr2obj(aTHX_ "Apache2::RequestRec", r)));
+    XPUSHs(sv_2mortal(newSVpv(require_args, 0)));
+    PUTBACK;
+    count = call_sv(ab->cb1, G_SCALAR);
+    SPAGAIN;
+
+    if (count == 1) {
+        ret = (authz_status) POPi;
+    }
+
+    PUTBACK;
+    FREETMPS;
+    LEAVE;
+    return ret;
+}
+
+static const char *perl_parse_require_line(cmd_parms *cmd,
+                                           const char *require_line,
+                                           const void **parsed_require_line)
+{
+    SV *ret_sv;
+    char *ret = NULL;
+    int count;
+
+    if (global_authz_providers == NULL) {
+        return ret;
+    }
+
+    void *key;
+    apr_pool_userdata_get(&key, AUTHZ_PROVIDER_NAME_NOTE, cmd->temp_pool);
+    auth_callback *ab = apr_hash_get(global_authz_providers, (char *) key,
+                                     APR_HASH_KEY_STRING);
+    if (ab == NULL || ab->cb2 == NULL) {
+        return ret;
+    }
+
+    modperl_interp_t *interp = 
modperl_interp_pool_select(cmd->server->process->pool,
+                                                          cmd->server);
+    dTHXa(interp->perl);
+    dSP;
+    ENTER;
+    SAVETMPS;
+    PUSHMARK(SP);
+    XPUSHs(sv_2mortal(modperl_ptr2obj(aTHX_ "Apache2::CmdParms", cmd)));
+    XPUSHs(sv_2mortal(newSVpv(require_line, 0)));
+    PUTBACK;
+    count = call_sv(ab->cb2, G_SCALAR);
+    SPAGAIN;
+
+    if (count == 1) {
+        ret_sv = POPs;
+        if (SvOK(ret_sv)) {
+            char *tmp = SvPV_nolen(ret_sv);
+            if (*tmp != '\0') {
+                ret = apr_pstrdup(cmd->pool, tmp);
+            }
+        }
+    }
+
+    PUTBACK;
+    FREETMPS;
+    LEAVE;
+    return ret;
+}
+
+static authn_status perl_check_password(request_rec *r, const char *user,
+                                        const char *password)
+{
+    authn_status ret = AUTH_DENIED;
+    int count;
+    AV *args = Nullav;
+
+    if (global_authn_providers == NULL) {
+        return ret;
+    }
+
+    const char *key = apr_table_get(r->notes, AUTHN_PROVIDER_NAME_NOTE);
+    auth_callback *ab = apr_hash_get(global_authn_providers, key,
+                                     APR_HASH_KEY_STRING);
+    if (ab == NULL || ab->cb1) {
+        return ret;
+    }
+
+    MP_dTHX;
+
+    if (ab->cb1 == NULL) {
+        if (ab->cb1_handler == NULL) {
+            return ret;
+        }
+
+        modperl_handler_make_args(aTHX_ &args, "Apache2::RequestRec", r,
+                                  "PV", user,
+                                  "PV", password, NULL);
+        ret = modperl_callback(aTHX_ ab->cb1_handler, r->pool, r, r->server,
+                               args);
+        SvREFCNT_dec((SV*)args);
+        return ret;
+    }
+
+    dSP;
+    ENTER;
+    SAVETMPS;
+    PUSHMARK(SP);
+    XPUSHs(sv_2mortal(modperl_ptr2obj(aTHX_ "Apache2::RequestRec", r)));
+    XPUSHs(sv_2mortal(newSVpv(user, 0)));
+    XPUSHs(sv_2mortal(newSVpv(password, 0)));
+    PUTBACK;
+    count = call_sv(ab->cb1, G_SCALAR);
+    SPAGAIN;
+
+    if (count == 1) {
+        ret = (authn_status) POPi;
+    }
+
+    PUTBACK;
+    FREETMPS;
+    LEAVE;
+    return ret;
+}
+
+static authn_status perl_get_realm_hash(request_rec *r, const char *user,
+                                        const char *realm, char **rethash)
+{
+    authn_status ret = AUTH_USER_NOT_FOUND;
+    int count;
+    SV *rh;
+
+    if (global_authn_providers == NULL) {
+        return ret;
+    }
+
+    const char *key = apr_table_get(r->notes, AUTHN_PROVIDER_NAME_NOTE);
+    auth_callback *ab = apr_hash_get(global_authn_providers, key,
+                                     APR_HASH_KEY_STRING);
+    if (ab == NULL || ab->cb2) {
+        return ret;
+    }
+
+    MP_dTHX;
+    rh = sv_2mortal(newSVpv("", 0));
+    dSP;
+    ENTER;
+    SAVETMPS;
+    PUSHMARK(SP);
+    XPUSHs(sv_2mortal(modperl_ptr2obj(aTHX_ "Apache2::RequestRec", r)));
+    XPUSHs(sv_2mortal(newSVpv(user, 0)));
+    XPUSHs(sv_2mortal(newSVpv(realm, 0)));
+    XPUSHs(newRV_noinc(rh));
+    PUTBACK;
+    count = call_sv(ab->cb2, G_SCALAR);
+    SPAGAIN;
+
+    if (count == 1) {
+        ret = (authn_status) POPi;
+        char *tmp = SvPV_nolen(rh);
+        if (*tmp != '\0') {
+            *rethash = apr_pstrdup(r->pool, tmp);
+        }
+    }
+
+    PUTBACK;
+    FREETMPS;
+    LEAVE;
+    return ret;
+}
+
+static const authz_provider authz_perl_provider = { perl_check_authorization,
+                                                    perl_parse_require_line };
+
+static const authn_provider authn_perl_provider = { perl_check_password,
+                                                    perl_get_realm_hash };
+
+static apr_status_t register_auth_provider(apr_pool_t *pool,
+                                           const char *provider_group,
+                                           const char *provider_name,
+                                           const char *provider_version,
+                                           auth_callback *ab, int type)
+{
+    void *provider_ = NULL;
+
+    if (global_authz_providers == NULL) {
+        global_authz_providers = apr_hash_make(pool);
+        global_authn_providers = apr_hash_make(pool);
+        /* We have to use pre_cleanup here, otherwise this cleanup method
+         * would be called after another cleanup method which unloads
+         * mod_perl module.
+         */
+        apr_pool_pre_cleanup_register(pool, NULL,
+                                      cleanup_perl_global_providers);
+    }
+
+    if (strcmp(provider_group, AUTHZ_PROVIDER_GROUP) == 0) {
+        provider_ = (void *) &authz_perl_provider;
+        apr_hash_set(global_authz_providers, provider_name,
+                     APR_HASH_KEY_STRING, ab);
+    }
+    else {
+        provider_ = (void *) &authn_perl_provider;
+        apr_hash_set(global_authn_providers, provider_name,
+                     APR_HASH_KEY_STRING, ab);
+    }
+
+    return ap_register_auth_provider(pool, provider_group, provider_name,
+                                     provider_version, provider_, type);
+
+}
+
+apr_status_t modperl_register_auth_provider(apr_pool_t *pool,
+                                            const char *provider_group,
+                                            const char *provider_name,
+                                            const char *provider_version,
+                                            SV *callback1, SV *callback2,
+                                            int type)
+{
+    char *provider_name_dup;
+    auth_callback *ab = NULL;
+
+    provider_name_dup = apr_pstrdup(pool, provider_name);
+    ab = apr_pcalloc(pool, sizeof(auth_callback));
+    ab->cb1 = callback1;
+    ab->cb2 = callback2;
+
+    return register_auth_provider(pool, provider_group, provider_name_dup,
+                                  provider_version, ab, type);
+}
+
+apr_status_t modperl_register_auth_provider_name(apr_pool_t *pool,
+                                                 const char *provider_group,
+                                                 const char *provider_name,
+                                                 const char *provider_version,
+                                                 const char *callback1,
+                                                 const char *callback2,
+                                                 int type)
+{
+    char *provider_name_dup;
+    auth_callback *ab = NULL;
+
+    provider_name_dup = apr_pstrdup(pool, provider_name);
+    ab = apr_pcalloc(pool, sizeof(auth_callback));
+    ab->cb1_handler = modperl_handler_new(pool, callback1);
+    if (callback2) {
+        ab->cb2_handler = modperl_handler_new(pool, callback2);
+    }
+
+    return register_auth_provider(pool, provider_group, provider_name_dup,
+                                  provider_version, ab, type);
+}

Modified: perl/modperl/branches/httpd24/src/modules/perl/modperl_util.h
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/src/modules/perl/modperl_util.h?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/src/modules/perl/modperl_util.h (original)
+++ perl/modperl/branches/httpd24/src/modules/perl/modperl_util.h Wed Feb 20 
11:40:50 2013
@@ -151,4 +151,18 @@ SV *modperl_pnotes(pTHX_ HV **pnotes, SV
 
 U16 *modperl_code_attrs(pTHX_ CV *cv);
 
+apr_status_t
+modperl_register_auth_provider(apr_pool_t *pool, const char *provider_group,
+                               const char *provider_name,
+                               const char *provider_version, SV *callback1,
+                               SV *callback2, int type);
+
+apr_status_t
+modperl_register_auth_provider_name(apr_pool_t *pool,
+                                    const char *provider_group,
+                                    const char *provider_name,
+                                    const char *provider_version,
+                                    const char *callback1,
+                                    const char *callback2, int type);
+
 #endif /* MODPERL_UTIL_H */

Modified: 
perl/modperl/branches/httpd24/xs/Apache2/RequestUtil/Apache2__RequestUtil.h
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/xs/Apache2/RequestUtil/Apache2__RequestUtil.h?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/xs/Apache2/RequestUtil/Apache2__RequestUtil.h 
(original)
+++ perl/modperl/branches/httpd24/xs/Apache2/RequestUtil/Apache2__RequestUtil.h 
Wed Feb 20 11:40:50 2013
@@ -349,3 +349,49 @@ void mpxs_Apache2__RequestRec_child_term
     apr_pool_cleanup_register(r->pool, r->pool, child_terminate,
                               apr_pool_cleanup_null);
 }
+
+
+
+static MP_INLINE
+apr_status_t mpxs_ap_register_auth_provider(pTHX_ I32 items, SV **MARK, SV 
**SP)
+{
+    if (items != 7)
+       Perl_croak(aTHX_ "pool, provider_group, provider_name, "
+                        "provider_version, callback1, callback2, type");
+
+    apr_pool_t *pool;
+
+    if (SvROK(*MARK) && sv_derived_from(*MARK, "APR::Pool")) {
+        IV tmp = SvIV((SV*)SvRV(*MARK));
+            if (tmp == 0) {
+                Perl_croak(aTHX_ "invalid pool object (already destroyed?)");
+            }
+        pool = INT2PTR(APR__Pool, tmp);
+    }
+    else {
+        Perl_croak(aTHX_ SvROK(*MARK) ?
+                       "pool is not of type APR::Pool" :
+                       "pool is not a blessed reference");
+        }
+
+    MARK++;
+    const char *provider_group = (const char *)SvPV_nolen(*MARK);
+    MARK++;
+    const char *provider_name = (const char *)SvPV_nolen(*MARK);
+    MARK++;
+    const char *provider_version = (const char *)SvPV_nolen(*MARK);
+    MARK++;
+    SV *callback1 = newSVsv(*MARK);
+    MARK++;
+    SV *callback2 = NULL;
+    if (SvROK(*MARK)) {
+        callback2 = newSVsv(*MARK);
+    }
+    MARK++;
+    int type = (int)SvIV(*MARK);
+
+    return modperl_register_auth_provider(pool, provider_group, provider_name,
+                                          provider_version, callback1,
+                                          callback2, type);
+}
+

Modified: perl/modperl/branches/httpd24/xs/maps/apache2_functions.map
URL: 
http://svn.apache.org/viewvc/perl/modperl/branches/httpd24/xs/maps/apache2_functions.map?rev=1448098&r1=1448097&r2=1448098&view=diff
==============================================================================
--- perl/modperl/branches/httpd24/xs/maps/apache2_functions.map (original)
+++ perl/modperl/branches/httpd24/xs/maps/apache2_functions.map Wed Feb 20 
11:40:50 2013
@@ -37,6 +37,7 @@
 
 MODULE=Apache2::RequestUtil
  ap_get_status_line
+ ap_register_auth_provider | mpxs_ | ...
 
 MODULE=Apache2::RequestUtil   PACKAGE=guess
  ap_psignature | | r, prefix
@@ -541,3 +542,6 @@ MODULE=Apache2::MPM   PACKAGE=Apache2::M
 ?ap_mpm_set_pidfile
 ?ap_mpm_set_scoreboard
 ?ap_listen_pre_config
+
+MODULE=Apache2::Provider
+ ap_register_provider


Reply via email to