blob: e804bad624319e3a86bc70346cce72bd3059413a [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mod_perl.h"
typedef struct {
modperl_mgv_t *dir_create;
modperl_mgv_t *dir_merge;
modperl_mgv_t *srv_create;
modperl_mgv_t *srv_merge;
int namelen;
} modperl_module_info_t;
typedef struct {
server_rec *server;
modperl_module_info_t *minfo;
} modperl_module_cfg_t;
#define MP_MODULE_INFO(modp) \
(modperl_module_info_t *)modp->dynamic_load_handle
#define MP_MODULE_CFG_MINFO(ptr) \
((modperl_module_cfg_t *)ptr)->minfo
static modperl_module_cfg_t *modperl_module_cfg_new(apr_pool_t *p)
{
modperl_module_cfg_t *cfg =
(modperl_module_cfg_t *)apr_pcalloc(p, sizeof(*cfg));
return cfg;
}
static modperl_module_cmd_data_t *modperl_module_cmd_data_new(apr_pool_t *p)
{
modperl_module_cmd_data_t *cmd_data =
(modperl_module_cmd_data_t *)apr_pcalloc(p, sizeof(*cmd_data));
return cmd_data;
}
static void *modperl_module_config_dir_create(apr_pool_t *p, char *dir)
{
return modperl_module_cfg_new(p);
}
static void *modperl_module_config_srv_create(apr_pool_t *p, server_rec *s)
{
return modperl_module_cfg_new(p);
}
static SV **modperl_module_config_hash_get(pTHX_ int create)
{
SV **svp;
/* XXX: could make this lookup faster */
svp = hv_fetch(PL_modglobal,
"ModPerl::Module::ConfigTable",
MP_SSTRLEN("ModPerl::Module::ConfigTable"),
create);
return svp;
}
void modperl_module_config_table_set(pTHX_ PTR_TBL_t *table)
{
SV **svp = modperl_module_config_hash_get(aTHX_ TRUE);
sv_setiv(*svp, PTR2IV(table));
}
PTR_TBL_t *modperl_module_config_table_get(pTHX_ int create)
{
PTR_TBL_t *table = NULL;
SV *sv, **svp = modperl_module_config_hash_get(aTHX_ create);
if (!svp) {
return NULL;
}
sv = *svp;
if (!SvIOK(sv) && create) {
table = modperl_svptr_table_new(aTHX);
sv_setiv(sv, PTR2IV(table));
}
else {
table = INT2PTR(PTR_TBL_t *, SvIV(sv));
}
return table;
}
typedef struct {
#ifdef USE_ITHREADS
modperl_interp_t *interp;
#endif
PTR_TBL_t *table;
void *ptr;
} config_obj_cleanup_t;
/*
* any per-dir CREATE or MERGE that happens at request time
* needs to be removed from the pointer table.
*/
static apr_status_t modperl_module_config_obj_cleanup(void *data)
{
config_obj_cleanup_t *cleanup =
(config_obj_cleanup_t *)data;
#ifdef USE_ITHREADS
dTHXa(cleanup->interp->perl);
MP_ASSERT_CONTEXT(aTHX);
#endif
modperl_svptr_table_delete(aTHX_ cleanup->table, cleanup->ptr);
MP_TRACE_c(MP_FUNC, "deleting ptr %pp from table %pp",
cleanup->ptr, cleanup->table);
MP_INTERP_PUTBACK(cleanup->interp, aTHX);
return APR_SUCCESS;
}
static void modperl_module_config_obj_cleanup_register(pTHX_
apr_pool_t *p,
PTR_TBL_t *table,
void *ptr)
{
config_obj_cleanup_t *cleanup =
(config_obj_cleanup_t *)apr_palloc(p, sizeof(*cleanup));
cleanup->table = table;
cleanup->ptr = ptr;
#ifdef USE_ITHREADS
cleanup->interp = modperl_thx_interp_get(aTHX);
MP_INTERP_REFCNT_inc(cleanup->interp);
#endif
apr_pool_cleanup_register(p, cleanup,
modperl_module_config_obj_cleanup,
apr_pool_cleanup_null);
}
#define MP_CFG_MERGE_DIR 1
#define MP_CFG_MERGE_SRV 2
/*
* XXX: vhosts may have different parent interpreters.
*/
static void *modperl_module_config_merge(apr_pool_t *p,
void *basev, void *addv,
int type)
{
GV *gv;
modperl_mgv_t *method;
modperl_module_cfg_t *mrg = NULL,
*tmp,
*base = (modperl_module_cfg_t *)basev,
*add = (modperl_module_cfg_t *)addv;
server_rec *s;
int is_startup;
PTR_TBL_t *table;
SV *mrg_obj = (SV *)NULL, *base_obj, *add_obj;
MP_dINTERP;
/* if the module is loaded in vhost, base==NULL */
tmp = (base && base->server) ? base : add;
if (tmp && !tmp->server) {
/* no directives for this module were encountered so far */
return basev;
}
s = tmp->server;
is_startup = (p == s->process->pconf);
MP_INTERP_POOLa(p, s);
table = modperl_module_config_table_get(aTHX_ TRUE);
base_obj = modperl_svptr_table_fetch(aTHX_ table, base);
add_obj = modperl_svptr_table_fetch(aTHX_ table, add);
if (!base_obj || (base_obj == add_obj)) {
MP_INTERP_PUTBACK(interp, aTHX);
return addv;
}
mrg = modperl_module_cfg_new(p);
memcpy(mrg, tmp, sizeof(*mrg));
method = (type == MP_CFG_MERGE_DIR) ?
mrg->minfo->dir_merge :
mrg->minfo->srv_merge;
if (method && (gv = modperl_mgv_lookup(aTHX_ method))) {
int count;
dSP;
MP_TRACE_c(MP_FUNC, "calling %s->%s",
SvCLASS(base_obj), modperl_mgv_last_name(method));
ENTER;SAVETMPS;
PUSHMARK(sp);
XPUSHs(base_obj);XPUSHs(add_obj);
PUTBACK;
count = call_sv((SV*)GvCV(gv), G_EVAL|G_SCALAR);
SPAGAIN;
if (count == 1) {
mrg_obj = SvREFCNT_inc(POPs);
}
PUTBACK;
FREETMPS;LEAVE;
if (SvTRUE(ERRSV)) {
/* XXX: should die here. */
(void)modperl_errsv(aTHX_ HTTP_INTERNAL_SERVER_ERROR,
NULL, NULL);
}
}
else {
mrg_obj = SvREFCNT_inc(add_obj);
}
modperl_svptr_table_store(aTHX_ table, mrg, mrg_obj);
if (!is_startup) {
modperl_module_config_obj_cleanup_register(aTHX_ p, table, mrg);
}
MP_INTERP_PUTBACK(interp, aTHX);
return (void *)mrg;
}
static void *modperl_module_config_dir_merge(apr_pool_t *p,
void *basev, void *addv)
{
return modperl_module_config_merge(p, basev, addv,
MP_CFG_MERGE_DIR);
}
static void *modperl_module_config_srv_merge(apr_pool_t *p,
void *basev, void *addv)
{
return modperl_module_config_merge(p, basev, addv,
MP_CFG_MERGE_SRV);
}
#define modperl_bless_cmd_parms(parms) \
sv_2mortal(modperl_ptr2obj(aTHX_ "Apache2::CmdParms", (void *)parms))
static const char *
modperl_module_config_create_obj(pTHX_
apr_pool_t *p,
PTR_TBL_t *table,
modperl_module_cfg_t *cfg,
modperl_module_cmd_data_t *info,
modperl_mgv_t *method,
cmd_parms *parms,
SV **obj)
{
const char *mname = info->modp->name;
modperl_module_info_t *minfo = MP_MODULE_INFO(info->modp);
GV *gv;
int is_startup = (p == parms->server->process->pconf);
/*
* XXX: if MPM is not threaded, we could modify the
* modperl_module_cfg_t * directly and avoid the ptr_table
* altogether.
*/
if ((*obj = (SV*)modperl_svptr_table_fetch(aTHX_ table, cfg))) {
/* object already exists */
return NULL;
}
MP_TRACE_c(MP_FUNC, "%s cfg=0x%lx for %s.%s",
method ? modperl_mgv_last_name(method) : "NULL",
(unsigned long)cfg, mname, parms->cmd->name);
/* used by merge functions to get a Perl interp */
cfg->server = parms->server;
cfg->minfo = minfo;
if (method && (gv = modperl_mgv_lookup(aTHX_ method))) {
int count;
dSP;
ENTER;SAVETMPS;
PUSHMARK(sp);
XPUSHs(sv_2mortal(newSVpv(mname, minfo->namelen)));
XPUSHs(modperl_bless_cmd_parms(parms));
PUTBACK;
count = call_sv((SV*)GvCV(gv), G_EVAL|G_SCALAR);
SPAGAIN;
if (count == 1) {
*obj = SvREFCNT_inc(POPs);
}
PUTBACK;
FREETMPS;LEAVE;
if (SvTRUE(ERRSV)) {
return SvPVX(ERRSV);
}
}
else {
HV *stash = gv_stashpvn(mname, minfo->namelen, FALSE);
/* return bless {}, $class */
*obj = newRV_noinc((SV*)newHV());
*obj = sv_bless(*obj, stash);
}
if (!is_startup) {
modperl_module_config_obj_cleanup_register(aTHX_ p, table, cfg);
}
modperl_svptr_table_store(aTHX_ table, cfg, *obj);
return NULL;
}
#define PUSH_STR_ARG(arg) \
if (arg) XPUSHs(sv_2mortal(newSVpv(arg,0)))
static const char *modperl_module_cmd_take123(cmd_parms *parms,
void *mconfig,
const char *one,
const char *two,
const char *three)
{
modperl_module_cfg_t *cfg = (modperl_module_cfg_t *)mconfig;
const char *retval = NULL, *errmsg;
const command_rec *cmd = parms->cmd;
server_rec *s = parms->server;
apr_pool_t *p = parms->pool;
modperl_module_cmd_data_t *info =
(modperl_module_cmd_data_t *)cmd->cmd_data;
modperl_module_info_t *minfo = MP_MODULE_INFO(info->modp);
modperl_module_cfg_t *srv_cfg;
int modules_alias = 0;
int count;
PTR_TBL_t *table;
SV *obj = (SV *)NULL;
MP_dINTERP_POOLa(p, s);
table = modperl_module_config_table_get(aTHX_ TRUE);
if (s->is_virtual) {
MP_dSCFG(s);
/* if the Perl module is loaded in the base server and a vhost
* has configuration directives from that module, but no
* mod_perl.c directives, scfg == NULL when
* modperl_module_cmd_take123 is run. If the directive
* callback wants to do something with the mod_perl config
* object, it'll segfault, since it doesn't exist yet, because
* this happens before server configs are merged. So we create
* a temp struct and fill it in with things that might be
* needed by the Perl callback.
*/
if (!scfg) {
scfg = modperl_config_srv_new(p, s);
modperl_set_module_config(s->module_config, scfg);
scfg->server = s;
}
/* if PerlLoadModule Foo is called from the base server, but
* Foo's directives are used inside a vhost, we need to
* temporary link to the base server config's 'modules'
* member. e.g. so Apache2::Module->get_config() can be called
* from a custom directive's callback, before the server/vhost
* config merge is performed
*/
if (!scfg->modules) {
modperl_config_srv_t *base_scfg =
modperl_config_srv_get(modperl_global_get_server_rec());
if (base_scfg->modules) {
scfg->modules = base_scfg->modules;
modules_alias = 1;
}
}
}
errmsg = modperl_module_config_create_obj(aTHX_ p, table, cfg, info,
minfo->dir_create,
parms, &obj);
if (errmsg) {
MP_INTERP_PUTBACK(interp, aTHX);
return errmsg;
}
if (obj) {
MP_TRACE_c(MP_FUNC, "found per-dir obj=0x%lx for %s.%s",
(unsigned long)obj,
info->modp->name, cmd->name);
}
/* XXX: could delay creation of srv_obj until
* Apache2::ModuleConfig->get is called.
*/
srv_cfg = ap_get_module_config(s->module_config, info->modp);
if (srv_cfg) {
SV *srv_obj;
errmsg = modperl_module_config_create_obj(aTHX_ p, table, srv_cfg, info,
minfo->srv_create,
parms, &srv_obj);
if (errmsg) {
MP_INTERP_PUTBACK(interp, aTHX);
return errmsg;
}
if (srv_obj) {
MP_TRACE_c(MP_FUNC, "found per-srv obj=0x%lx for %s.%s",
(unsigned long)srv_obj,
info->modp->name, cmd->name);
}
}
{
dSP;
ENTER;SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, 2);
PUSHs(obj);
PUSHs(modperl_bless_cmd_parms(parms));
if (cmd->args_how != NO_ARGS) {
PUSH_STR_ARG(one);
PUSH_STR_ARG(two);
PUSH_STR_ARG(three);
}
PUTBACK;
count = call_method(info->func_name, G_EVAL|G_SCALAR);
SPAGAIN;
if (count == 1) {
SV *sv = POPs;
if (SvPOK(sv) && strEQ(SvPVX(sv), DECLINE_CMD)) {
retval = DECLINE_CMD;
}
}
PUTBACK;
FREETMPS;LEAVE;
}
if (SvTRUE(ERRSV)) {
retval = SvPVX(ERRSV);
}
MP_INTERP_PUTBACK(interp, aTHX);
if (modules_alias) {
MP_dSCFG(s);
/* unalias the temp aliasing */
scfg->modules = NULL;
}
return retval;
}
static const char *modperl_module_cmd_take1(cmd_parms *parms,
void *mconfig,
const char *one)
{
return modperl_module_cmd_take123(parms, mconfig, one, NULL, NULL);
}
static const char *modperl_module_cmd_take2(cmd_parms *parms,
void *mconfig,
const char *one,
const char *two)
{
return modperl_module_cmd_take123(parms, mconfig, one, two, NULL);
}
static const char *modperl_module_cmd_flag(cmd_parms *parms,
void *mconfig,
int flag)
{
char buf[2];
apr_snprintf(buf, sizeof(buf), "%d", flag);
return modperl_module_cmd_take123(parms, mconfig, buf, NULL, NULL);
}
static const char *modperl_module_cmd_no_args(cmd_parms *parms,
void *mconfig)
{
return modperl_module_cmd_take123(parms, mconfig, NULL, NULL, NULL);
}
#define modperl_module_cmd_raw_args modperl_module_cmd_take1
#define modperl_module_cmd_iterate modperl_module_cmd_take1
#define modperl_module_cmd_iterate2 modperl_module_cmd_take2
#define modperl_module_cmd_take12 modperl_module_cmd_take2
#define modperl_module_cmd_take23 modperl_module_cmd_take123
#define modperl_module_cmd_take3 modperl_module_cmd_take123
#define modperl_module_cmd_take13 modperl_module_cmd_take123
#if defined(AP_HAVE_DESIGNATED_INITIALIZER)
# define modperl_module_cmd_func_set(cmd, name) \
cmd->func.name = modperl_module_cmd_##name
#else
# define modperl_module_cmd_func_set(cmd, name) \
cmd->func = modperl_module_cmd_##name
#endif
static int modperl_module_cmd_lookup(command_rec *cmd)
{
switch (cmd->args_how) {
case TAKE1:
case ITERATE:
modperl_module_cmd_func_set(cmd, take1);
break;
case TAKE2:
case ITERATE2:
case TAKE12:
modperl_module_cmd_func_set(cmd, take2);
break;
case TAKE3:
case TAKE23:
case TAKE123:
case TAKE13:
modperl_module_cmd_func_set(cmd, take3);
break;
case RAW_ARGS:
modperl_module_cmd_func_set(cmd, raw_args);
break;
case FLAG:
modperl_module_cmd_func_set(cmd, flag);
break;
case NO_ARGS:
modperl_module_cmd_func_set(cmd, no_args);
break;
default:
return FALSE;
}
return TRUE;
}
static apr_status_t modperl_module_remove(void *data)
{
module *modp = (module *)data;
ap_remove_loaded_module(modp);
return APR_SUCCESS;
}
static const char *modperl_module_cmd_fetch(pTHX_ SV *obj,
const char *name, SV **retval)
{
const char *errmsg = NULL;
if (*retval) {
SvREFCNT_dec(*retval);
*retval = (SV *)NULL;
}
if (sv_isobject(obj)) {
int count;
dSP;
ENTER;SAVETMPS;
PUSHMARK(SP);
XPUSHs(obj);
PUTBACK;
count = call_method(name, G_EVAL|G_SCALAR);
SPAGAIN;
if (count == 1) {
SV *sv = POPs;
if (SvTRUE(sv)) {
*retval = SvREFCNT_inc(sv);
}
}
if (!*retval) {
errmsg = Perl_form(aTHX_ "%s->%s did not return a %svalue",
SvCLASS(obj), name, count ? "true " : "");
}
PUTBACK;
FREETMPS;LEAVE;
if (SvTRUE(ERRSV)) {
errmsg = SvPVX(ERRSV);
}
}
else if (SvROK(obj) && (SvTYPE(SvRV(obj)) == SVt_PVHV)) {
HV *hv = (HV*)SvRV(obj);
SV **svp = hv_fetch(hv, name, strlen(name), 0);
if (svp) {
*retval = SvREFCNT_inc(*svp);
}
else {
errmsg = Perl_form(aTHX_ "HASH key %s does not exist", name);
}
}
else {
errmsg = "command entry is not an object or a HASH reference";
}
return errmsg;
}
static const char *modperl_module_add_cmds(apr_pool_t *p, server_rec *s,
module *modp, SV *mod_cmds)
{
const char *errmsg;
apr_array_header_t *cmds;
command_rec *cmd;
AV *module_cmds;
I32 i, fill;
MP_dINTERPa(NULL, NULL, s);
module_cmds = (AV*)SvRV(mod_cmds);
fill = AvFILL(module_cmds);
cmds = apr_array_make(p, fill+1, sizeof(command_rec));
for (i=0; i<=fill; i++) {
SV *val = (SV *)NULL;
STRLEN len;
SV *obj = AvARRAY(module_cmds)[i];
modperl_module_cmd_data_t *info = modperl_module_cmd_data_new(p);
info->modp = modp;
cmd = apr_array_push(cmds);
if ((errmsg = modperl_module_cmd_fetch(aTHX_ obj, "name", &val))) {
MP_INTERP_PUTBACK(interp, aTHX);
return errmsg;
}
cmd->name = apr_pstrdup(p, SvPV(val, len));
if ((errmsg = modperl_module_cmd_fetch(aTHX_ obj, "args_how", &val))) {
/* XXX default based on $self->func prototype */
cmd->args_how = TAKE1; /* default */
}
else {
if (SvIOK(val)) {
cmd->args_how = SvIV(val);
}
else {
cmd->args_how =
SvIV(modperl_constants_lookup_apache2_const(aTHX_ SvPV(val, len)));
}
}
if (!modperl_module_cmd_lookup(cmd)) {
MP_INTERP_PUTBACK(interp, aTHX);
return apr_psprintf(p,
"no command function defined for args_how=%d",
cmd->args_how);
}
if ((errmsg = modperl_module_cmd_fetch(aTHX_ obj, "func", &val))) {
info->func_name = cmd->name; /* default */
}
else {
info->func_name = apr_pstrdup(p, SvPV(val, len));
}
if ((errmsg = modperl_module_cmd_fetch(aTHX_ obj, "req_override", &val))) {
cmd->req_override = OR_ALL; /* default */
}
else {
if (SvIOK(val)) {
cmd->req_override = SvIV(val);
}
else {
cmd->req_override =
SvIV(modperl_constants_lookup_apache2_const(aTHX_ SvPV(val, len)));
}
}
if ((errmsg = modperl_module_cmd_fetch(aTHX_ obj, "errmsg", &val))) {
/* default */
/* XXX generate help msg based on args_how */
cmd->errmsg = apr_pstrcat(p, cmd->name, " command", NULL);
}
else {
cmd->errmsg = apr_pstrdup(p, SvPV(val, len));
}
cmd->cmd_data = info;
/* no default if undefined */
if (!(errmsg = modperl_module_cmd_fetch(aTHX_ obj, "cmd_data", &val))) {
info->cmd_data = apr_pstrdup(p, SvPV(val, len));
}
if (val) {
SvREFCNT_dec(val);
val = (SV *)NULL;
}
}
cmd = apr_array_push(cmds);
cmd->name = NULL;
modp->cmds = (command_rec *)cmds->elts;
MP_INTERP_PUTBACK(interp, aTHX);
return NULL;
}
static void modperl_module_insert(module *modp)
{
/*
* insert after mod_perl, rather the top of the list.
* (see ap_add_module; does not insert into ap_top_module list if
* m->next != NULL)
* this way, modperl config merging happens before this module.
*/
modp->next = perl_module.next;
perl_module.next = modp;
}
#define MP_isGV(gv) (gv && isGV(gv))
static modperl_mgv_t *modperl_module_fetch_method(pTHX_
apr_pool_t *p,
module *modp,
const char *method)
{
modperl_mgv_t *mgv;
HV *stash = gv_stashpv(modp->name, FALSE);
GV *gv = gv_fetchmethod_autoload(stash, method, FALSE);
MP_TRACE_c(MP_FUNC, "looking for method %s in package `%s'...%sfound",
method, modp->name,
MP_isGV(gv) ? "" : "not ");
if (!MP_isGV(gv)) {
return NULL;
}
mgv = modperl_mgv_compile(aTHX_ p,
apr_pstrcat(p,
modp->name, "::", method, NULL));
return mgv;
}
const char *modperl_module_add(apr_pool_t *p, server_rec *s,
const char *name, SV *mod_cmds)
{
MP_dSCFG(s);
const char *errmsg;
module *modp;
modperl_module_info_t *minfo;
MP_dINTERPa(NULL, NULL, s);
modp = (module *)apr_pcalloc(p, sizeof(*modp));
minfo = (modperl_module_info_t *)apr_pcalloc(p, sizeof(*minfo));
/* STANDARD20_MODULE_STUFF */
modp->version = MODULE_MAGIC_NUMBER_MAJOR;
modp->minor_version = MODULE_MAGIC_NUMBER_MINOR;
modp->module_index = -1;
modp->name = apr_pstrdup(p, name);
modp->magic = MODULE_MAGIC_COOKIE;
/* use this slot for our context */
modp->dynamic_load_handle = minfo;
/*
* XXX: we should lookup here if the Perl methods exist,
* and set these pointers only if they do.
*/
modp->create_dir_config = modperl_module_config_dir_create;
modp->merge_dir_config = modperl_module_config_dir_merge;
modp->create_server_config = modperl_module_config_srv_create;
modp->merge_server_config = modperl_module_config_srv_merge;
minfo->namelen = strlen(name);
minfo->dir_create =
modperl_module_fetch_method(aTHX_ p, modp, "DIR_CREATE");
minfo->dir_merge =
modperl_module_fetch_method(aTHX_ p, modp, "DIR_MERGE");
minfo->srv_create =
modperl_module_fetch_method(aTHX_ p, modp, "SERVER_CREATE");
minfo->srv_merge =
modperl_module_fetch_method(aTHX_ p, modp, "SERVER_MERGE");
modp->cmds = NULL;
if ((errmsg = modperl_module_add_cmds(p, s, modp, mod_cmds))) {
MP_INTERP_PUTBACK(interp, aTHX);
return errmsg;
}
modperl_module_insert(modp);
mp_add_loaded_module(modp, p, modp->name);
apr_pool_cleanup_register(p, modp, modperl_module_remove,
apr_pool_cleanup_null);
ap_single_module_configure(p, s, modp);
if (!scfg->modules) {
scfg->modules = apr_hash_make(p);
}
apr_hash_set(scfg->modules, apr_pstrdup(p, name), APR_HASH_KEY_STRING, modp);
#ifdef USE_ITHREADS
/*
* if the Perl module is loaded in the base server and a vhost
* has configuration directives from that module, but no mod_perl.c
* directives, scfg == NULL when modperl_module_cmd_take123 is run.
* this happens before server configs are merged, so we stash a pointer
* to what will be merged as the parent interp later. i.e. "safe hack"
*/
if (!modperl_interp_pool_get(p)) {
/* for vhosts */
MP_TRACE_i(MP_FUNC, "set interp 0x%lx in pconf pool 0x%lx",
(unsigned long)scfg->mip->parent, (unsigned long)p);
modperl_interp_pool_set(p, scfg->mip->parent);
}
#endif
MP_INTERP_PUTBACK(interp, aTHX);
return NULL;
}
SV *modperl_module_config_get_obj(pTHX_ SV *pmodule, server_rec *s,
ap_conf_vector_t *v)
{
MP_dSCFG(s);
module *modp;
const char *name;
void *ptr;
PTR_TBL_t *table;
SV *obj;
if (!v) {
v = s->module_config;
}
if (SvROK(pmodule)) {
name = SvCLASS(pmodule);
}
else {
STRLEN n_a;
name = SvPV(pmodule, n_a);
}
if (!(scfg->modules &&
(modp = apr_hash_get(scfg->modules, name, APR_HASH_KEY_STRING)))) {
return &PL_sv_undef;
}
if (!(ptr = ap_get_module_config(v, modp))) {
return &PL_sv_undef;
}
if (!(table = modperl_module_config_table_get(aTHX_ FALSE))) {
return &PL_sv_undef;
}
if (!(obj = modperl_svptr_table_fetch(aTHX_ table, ptr))) {
return &PL_sv_undef;
}
return obj;
}
/*
* Local Variables:
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/