| /* |
| ** 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(ERROR_CLASS, FALSE); |
| if (stash == NULL) { |
| SV *pkg_name = newSVpv(class, 0); |
| Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, pkg_name, Nullsv); |
| 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 */ |