/* ** 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. */ #ifndef APREQ_XS_POSTPERL_H #define APREQ_XS_POSTPERL_H /* avoid namespace collisions from perl's XSUB.h */ #include "modperl_perl_unembed.h" /* required for modperl's T_HASHOBJ (typemap) */ #include "modperl_common_util.h" /* backward compatibility macros support */ #include "ppport.h" /* apr version info for modules */ #include "apr_version.h" /* ExtUtils::XSBuilder::ParseSoure trickery... */ typedef apreq_handle_t apreq_xs_handle_cgi_t; typedef apreq_handle_t apreq_xs_handle_apache2_t; typedef apr_table_t apreq_xs_param_table_t; typedef apr_table_t apreq_xs_cookie_table_t; typedef HV apreq_xs_error_t; typedef char* apreq_xs_subclass_t; #define APR__Request__Param__Table const apr_table_t * #define APR__BucketAlloc apr_bucket_alloc_t * #define HANDLE_CLASS "APR::Request" #define COOKIE_CLASS "APR::Request::Cookie" #define PARAM_CLASS "APR::Request::Param" #define ERROR_CLASS "APR::Request::Error" #define COOKIE_TABLE_CLASS "APR::Request::Cookie::Table" #define PARAM_TABLE_CLASS "APR::Request::Param::Table" struct apreq_xs_do_arg { const char *pkg; SV *parent, *sub; PerlInterpreter *perl; }; /** * @file apreq_xs_postperl.h * @brief XS include file for making Cookie.so and Request.so * */ /** * @defgroup XS Perl * @ingroup GLUE * @{ */ /** * Trace through magic objects & hashrefs looking for original object. * @param in The starting SV *. * @param key The first letter of key is used to search a hashref for * the desired object. * @return Reference to the object. */ APR_INLINE static SV *apreq_xs_find_obj(pTHX_ SV *in, const char key) { const char altkey[] = { '_', key }; while (in && SvROK(in)) { SV *sv = SvRV(in); switch (SvTYPE(sv)) { MAGIC *mg; SV **svp; case SVt_PVHV: if (SvMAGICAL(sv) && (mg = mg_find(sv,PERL_MAGIC_tied))) { in = mg->mg_obj; break; } else if ((svp = hv_fetch((HV *)sv, altkey+1, 1, FALSE)) || (svp = hv_fetch((HV *)sv, altkey, 2, FALSE))) { in = *svp; break; } Perl_croak(aTHX_ "attribute hash has no '%s' key!", key); case SVt_PVMG: if (SvOBJECT(sv) && SvIOKp(sv)) return in; default: Perl_croak(aTHX_ "panic: unsupported SV type: %d", SvTYPE(sv)); } } Perl_croak(aTHX_ "apreq_xs_find_obj: object attr `%c' not found", key); return NULL; } /* conversion function templates based on modperl-2's sv2request_rec */ static APR_INLINE SV *apreq_xs_object2sv(pTHX_ void *ptr, const char *class, SV *parent, const char *base) { SV *rv = sv_setref_pv(newSV(0), class, (void *)ptr); sv_magic(SvRV(rv), parent, PERL_MAGIC_ext, Nullch, 0); if (!sv_derived_from(rv, base)) Perl_croak(aTHX_ "apreq_xs_object2sv failed: " "target class %s isn't derived from %s", class, base); return rv; } APR_INLINE static SV *apreq_xs_handle2sv(pTHX_ apreq_handle_t *req, const char *class, SV *parent) { return apreq_xs_object2sv(aTHX_ req, class, parent, HANDLE_CLASS); } APR_INLINE static SV *apreq_xs_param2sv(pTHX_ apreq_param_t *p, const char *class, SV *parent) { if (class == NULL) { SV *rv = newSVpvn(p->v.data, p->v.dlen); if (apreq_param_is_tainted(p)) SvTAINTED_on(rv); else if (apreq_param_charset_get(p) == APREQ_CHARSET_UTF8) /* Setting the UTF8 flag on non-utf8 data is a security hole. * Let's see if coupling that decision with taintedness helps * resolve this issue. */ SvUTF8_on(rv); return rv; } return apreq_xs_object2sv(aTHX_ p, class, parent, PARAM_CLASS); } APR_INLINE static SV *apreq_xs_cookie2sv(pTHX_ apreq_cookie_t *c, const char *class, SV *parent) { if (class == NULL) { SV *rv = newSVpvn(c->v.data, c->v.dlen); if (apreq_cookie_is_tainted(c)) SvTAINTED_on(rv); /*XXX add charset fixups? */ return rv; } return apreq_xs_object2sv(aTHX_ c, class, parent, COOKIE_CLASS); } APR_INLINE static SV* apreq_xs_error2sv(pTHX_ apr_status_t s) { char buf[256]; SV *sv = newSV(0); sv_upgrade(sv, SVt_PVIV); apreq_strerror(s, buf, sizeof buf); sv_setpvn(sv, buf, strlen(buf)); SvPOK_on(sv); SvIVX(sv) = s; SvIOK_on(sv); SvREADONLY_on(sv); return sv; } APR_INLINE static SV *apreq_xs_sv2object(pTHX_ SV *sv, const char *class, const char attr) { SV *obj; MAGIC *mg; sv = apreq_xs_find_obj(aTHX_ sv, attr); /* XXX sv_derived_from is expensive; how to optimize it? */ if (sv_derived_from(sv, class)) { return SvRV(sv); } /* else check if parent (mg->mg_obj) is the right object type */ if ((mg = mg_find(SvRV(sv), PERL_MAGIC_ext)) != NULL && (obj = mg->mg_obj) != NULL && SvOBJECT(obj)) { sv = sv_2mortal(newRV_inc(obj)); if (sv_derived_from(sv, class)) return obj; } Perl_croak(aTHX_ "apreq_xs_sv2object: %s object not found", class); return NULL; } APR_INLINE static apreq_handle_t *apreq_xs_sv2handle(pTHX_ SV *sv) { SV *obj = apreq_xs_sv2object(aTHX_ sv, HANDLE_CLASS, 'r'); IV iv = SvIVX(obj); return INT2PTR(apreq_handle_t *, iv); } static APR_INLINE apreq_param_t *apreq_xs_sv2param(pTHX_ SV *sv) { SV *obj = apreq_xs_sv2object(aTHX_ sv, PARAM_CLASS, 'p'); IV iv = SvIVX(obj); return INT2PTR(apreq_param_t *, iv); } static APR_INLINE apreq_cookie_t *apreq_xs_sv2cookie(pTHX_ SV *sv) { SV *obj = apreq_xs_sv2object(aTHX_ sv, COOKIE_CLASS, 'c'); IV iv = SvIVX(obj); return INT2PTR(apreq_cookie_t *, iv); } static APR_INLINE void apreq_xs_croak(pTHX_ HV *data, SV *obj, apr_status_t rc, const char *func, const char *class) { HV *stash; stash = gv_stashpv(class, FALSE); if (stash == NULL) { ENTER; Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, newSVpv(class, 0), Nullsv); LEAVE; stash = gv_stashpv(class, TRUE); } if (obj != Nullsv) sv_setsv(*hv_fetch(data, "_r", 2, 1), sv_2mortal(newRV_inc(obj))); sv_setiv(*hv_fetch(data, "rc", 2, 1), rc); sv_setpv(*hv_fetch(data, "file", 4, 1), CopFILE(PL_curcop)); sv_setiv(*hv_fetch(data, "line", 4, 1), CopLINE(PL_curcop)); sv_setpv(*hv_fetch(data, "func", 4, 1), func); sv_setsv(ERRSV, sv_2mortal(sv_bless(newRV_noinc((SV*)data), stash))); Perl_croak(aTHX_ Nullch); } static APR_INLINE const char *apreq_xs_helper_class(pTHX_ SV **SP, SV *sv, const char *method) { PUSHMARK(SP); XPUSHs(sv); PUTBACK; call_method(method, G_SCALAR); SPAGAIN; sv = POPs; PUTBACK; return SvPV_nolen(sv); } /** @} */ #endif /* APREQ_XS_POSTPERL_H */