blob: f0ce7b7772b0f5cbf89c6d0e21761f960f5d01f5 [file] [log] [blame]
/* Copyright 2000-2004 The Apache Software Foundation
**
** Licensed 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.
*/
#define PERL_NO_GET_CONTEXT /* we want efficiency */
#ifdef WIN32
#ifdef uid_t
#define apache_uid_t uid_t
#undef uid_t
#endif
#define uid_t apache_uid_t
#ifdef gid_t
#define apache_gid_t gid_t
#undef gid_t
#endif
#define gid_t apache_gid_t
#ifdef stat
#define apache_stat stat
#undef stat
#endif
#ifdef lstat
#define apache_lstat lstat
#undef lstat
#endif
#ifdef isnan
#define apache_isnan isnan
#undef isnan
#endif
#ifdef sleep
#define apache_sleep sleep
#undef sleep
#endif
#endif /* WIN32 */
#undef __attribute__
#include "mod_perl.h"
#include "apache_request.h"
#include "patchlevel.h"
#ifdef WIN32
#undef uid_t
#ifdef apache_uid_t
#define uid_t apache_uid_t
#undef apache_uid_t
#endif
#undef gid_t
#ifdef apache_gid_t
#define gid_t apache_gid_t
#undef apache_gid_t
#endif
#ifdef apache_isnan
#undef isnan
#define isnan apache_isnan
#undef apache_isnan
#endif
#ifdef apache_lstat
#undef lstat
#define lstat apache_lstat
#undef apache_lstat
#endif
#ifdef apache_stat
#undef stat
#define stat apache_stat
#undef apache_stat
#endif
#ifdef apache_sleep
#undef sleep
#define sleep apache_sleep
#undef apache_sleep
#endif
#endif /* WIN32 */
typedef ApacheRequest * Apache__Request;
typedef ApacheUpload * Apache__Upload;
typedef struct {
SV *data;
SV *sub;
PerlInterpreter *perl;
} UploadHook;
#define XsUploadHook ((UploadHook *)RETVAL->hook_data)
#define XsUploadHookNew(p) (void *)ap_pcalloc(p, sizeof(UploadHook))
#ifdef USE_ITHREADS
#define XsUploadHookNew_perl XsUploadHook->perl = aTHX
#else
#define XsUploadHookNew_perl
#endif
#define XsUploadHookSet(slot, sv) \
if (RETVAL->hook_data) { \
if (XsUploadHook->slot) { \
SvREFCNT_dec(XsUploadHook->slot); \
} \
} \
else { \
RETVAL->hook_data = XsUploadHookNew(r->pool); \
XsUploadHookNew_perl; \
ap_register_cleanup(r->pool, (void*)XsUploadHook, \
upload_hook_cleanup, ap_null_cleanup); \
} \
XsUploadHook->slot = SvREFCNT_inc(sv)
#define ApacheUpload_fh(upload) upload->fp
#define ApacheUpload_name(upload) upload->name
#define ApacheUpload_filename(upload) upload->filename
#define ApacheUpload_next(upload) upload->next
#define ApacheUpload_tempname(upload) upload->tempname
#ifdef PerlIO
typedef PerlIO * ApreqInputStream;
/* XXX: or should this be #ifdef PERL_IMPLICIT_SYS ? */
#ifdef WIN32
# ifndef PerlIO_importFILE
# define PerlIO_importFILE(fp,flags) (PerlIO*)fp
# endif
#endif
#ifdef SFIO
#undef PerlIO_importFILE
#define PerlIO_importFILE(fp,flags) (PerlIO*)fp
#endif /*SFIO*/
#else /*PerlIO not defined*/
typedef FILE * ApreqInputStream;
#define PerlIO_importFILE(fp,flags) fp
#define PerlIO_write(a,b,c) fwrite((b),1,(c),(a))
#endif /*PerlIO*/
static char *r_keys[] = { "_r", "r", NULL };
static SV *r_key_sv(pTHX_ SV *in)
{
SV *sv;
int i;
for (i=0; r_keys[i]; i++) {
int klen = strlen(r_keys[i]);
if(hv_exists((HV*)SvRV(in), r_keys[i], klen) &&
(sv = *hv_fetch((HV*)SvRV(in),
r_keys[i], klen, FALSE)))
{
return sv;
}
}
return Nullsv;
}
static ApacheRequest *sv_2apreq(pTHX_ SV *sv)
{
if (SvROK(sv) && sv_derived_from(sv, "Apache::Request")) {
SV *obj = sv;
switch (SvTYPE(SvRV(obj))) {
case SVt_PVHV :
do {
obj = r_key_sv(aTHX_ obj);
} while (SvROK(obj) && (SvTYPE(SvRV(obj)) == SVt_PVHV));
break;
default:
break;
};
return (ApacheRequest *)SvIV((SV*)SvRV(obj));
}
else {
return ApacheRequest_new(perl_request_rec(NULL));
}
}
static SV *upload_bless(pTHX_ ApacheUpload *upload)
{
SV *sv = newSV(0);
sv_setref_pv(sv, "Apache::Upload", (void*)upload);
return sv;
}
static int upload_hook(void *ptr, char *buf, int len, ApacheUpload *upload)
{
UploadHook *hook = (UploadHook *)ptr;
#ifdef USE_ITHREADS
dTHXa(hook->perl);
#endif
if (!(upload->fp || ApacheRequest_tmpfile(upload->req, upload)))
return -1; /* error */
{
SV *sv;
dSP;
PUSHMARK(SP);
EXTEND(SP, 4);
ENTER;
SAVETMPS;
sv = sv_newmortal();
sv_setref_pv(sv, "Apache::Upload", (void*)upload);
PUSHs(sv);
sv = sv_2mortal(newSVpvn(buf,len));
SvTAINT(sv);
PUSHs(sv);
sv = sv_2mortal(newSViv(len));
SvTAINT(sv);
PUSHs(sv);
PUSHs(hook->data);
PUTBACK;
perl_call_sv(hook->sub, G_EVAL|G_DISCARD);
FREETMPS;
LEAVE;
}
if (SvTRUE(ERRSV))
return -1;
return fwrite(buf, 1, len, upload->fp);
}
static void upload_hook_cleanup(void *ptr)
{
UploadHook *hook = (UploadHook *)ptr;
#ifdef USE_ITHREADS
dTHXa(hook->perl);
#endif
if (hook->sub) {
SvREFCNT_dec(hook->sub);
hook->sub = Nullsv;
}
if (hook->data) {
SvREFCNT_dec(hook->data);
hook->data = Nullsv;
}
}
#define upload_push(upload) \
XPUSHs(sv_2mortal(upload_bless(upload)))
static void apreq_add_magic(pTHX_ SV *sv, SV *obj, ApacheRequest *req)
{
sv_magic(SvRV(sv), obj, '~', "dummy", -1);
SvMAGIC(SvRV(sv))->mg_ptr = (char *)req->r;
}
#ifdef CGI_COMPAT
static void register_uploads (pTHX_ ApacheRequest *req) {
ApacheUpload *upload;
for (upload = req->upload; upload; upload = upload->next) {
if(upload->fp && upload->filename) {
GV *gv = gv_fetchpv(upload->filename, TRUE, SVt_PVIO);
if (do_open(gv, "<&", 2, FALSE, 0, 0, upload->fp)) {
ap_register_cleanup(req->r->pool, (void*)gv,
apreq_close_handle, ap_null_cleanup);
}
}
}
}
#else
#define register_uploads(req)
#endif
MODULE = Apache::Request PACKAGE = Apache::Request PREFIX = ApacheRequest_
PROTOTYPES: DISABLE
BOOT:
av_push(perl_get_av("Apache::Request::ISA",TRUE), newSVpv("Apache",6));
Apache::Request
ApacheRequest_new(class, r, ...)
SV *class
Apache r
PREINIT:
int i;
SV *robj;
CODE:
class = class; /* -Wall */
robj = ST(1);
RETVAL = ApacheRequest_new(r);
register_uploads(aTHX_ RETVAL);
for (i=2; i<items; i+=2) {
char *key = SvPV(ST(i),na);
switch (toLOWER(*key)) {
case 'd':
if (strcaseEQ(key, "disable_uploads")) {
RETVAL->disable_uploads = (int)SvIV(ST(i+1));
break;
}
case 'h':
if (strcaseEQ(key, "hook_data")) {
XsUploadHookSet(data, ST(i+1));
break;
}
case 'p':
if (strcaseEQ(key, "post_max")) {
RETVAL->post_max = (int)SvIV(ST(i+1));
break;
}
case 't':
if (strcaseEQ(key, "temp_dir")) {
RETVAL->temp_dir = ap_pstrdup(r->pool,SvPV(ST(i+1), PL_na));
break;
}
case 'u':
if (strcaseEQ(key, "upload_hook")) {
XsUploadHookSet(sub, ST(i+1));
RETVAL->upload_hook = upload_hook;
break;
}
default:
croak("[libapreq] unknown attribute: `%s'", key);
}
}
OUTPUT:
RETVAL
CLEANUP:
apreq_add_magic(aTHX_ ST(0), robj, RETVAL);
char *
ApacheRequest_script_name(req)
Apache::Request req
int
ApacheRequest_parse(req)
Apache::Request req
Apache::Table
ApacheRequest_query_params(req)
Apache::Request req
PREINIT:
table *parms;
CODE:
parms = ApacheRequest_query_params(req, req->r->pool);
ST(0) = mod_perl_tie_table(parms);
Apache::Table
ApacheRequest_post_params(req)
Apache::Request req
PREINIT:
table *parms;
CODE:
parms = ApacheRequest_post_params(req, req->r->pool);
ST(0) = mod_perl_tie_table(parms);
void
ApacheRequest_parms(req, parms=NULL)
Apache::Request req
Apache::Table parms
CODE:
if (parms) {
req->parms = parms->utable;
req->parsed = 1;
}
else {
ApacheRequest_parse(req);
}
ST(0) = mod_perl_tie_table(req->parms);
void
ApacheRequest_param(req, key=NULL, sv=Nullsv)
Apache::Request req
char *key
SV *sv
PPCODE:
if ( !req->parsed ) ApacheRequest_parse(req);
if (key) {
if (sv != Nullsv) {
if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) {
I32 i;
AV *av = (AV*)SvRV(sv);
const char *val;
ap_table_unset(req->parms, key);
for (i=0; i<=AvFILL(av); i++) {
val = (const char *)SvPV(*av_fetch(av, i, FALSE),PL_na);
ap_table_add(req->parms, key, val);
}
}
else ap_table_set(req->parms, key, (const char *)SvPV(sv, PL_na));
}
switch (GIMME_V) {
case G_SCALAR: /* return (first) parameter value */
{
const char *val = ap_table_get(req->parms, key);
if (val) XPUSHs(sv_2mortal(newSVpv((char*)val,0)));
else XSRETURN_UNDEF;
}
break;
case G_ARRAY: /* return list of parameter values */
{
I32 i;
array_header *arr = ap_table_elts(req->parms);
table_entry *elts = (table_entry *)arr->elts;
for (i = 0; i < arr->nelts; ++i) {
if (elts[i].key && strcaseEQ(elts[i].key, key))
XPUSHs(sv_2mortal(newSVpv(elts[i].val,0)));
}
}
break;
default:
XSRETURN_UNDEF;
}
}
else {
switch (GIMME_V) {
case G_SCALAR: /* like $apr->parms */
ST(0) = mod_perl_tie_table(req->parms);
XSRETURN(1);
break;
case G_ARRAY: /* return list of unique keys */
{
I32 i;
array_header *arr = ap_table_elts(req->parms);
table_entry *elts = (table_entry *)arr->elts;
for (i = 0; i < arr->nelts; ++i) {
I32 j;
if (!elts[i].key) continue;
/* simple but inefficient uniqueness check */
for (j = 0; j < i; ++j) {
if (strcaseEQ(elts[i].key, elts[j].key))
break;
}
if ( i == j )
XPUSHs(sv_2mortal(newSVpv(elts[i].key,0)));
}
}
break;
default:
XSRETURN_UNDEF;
}
}
void
ApacheRequest_upload(req, sv=Nullsv)
Apache::Request req
SV *sv
PREINIT:
ApacheUpload *uptr;
PPCODE:
if (sv && SvOBJECT(sv) && sv_isa(sv, "Apache::Upload")) {
req->upload = (ApacheUpload *)SvIV((SV*)SvRV(sv));
XSRETURN_EMPTY;
}
if ( !req->parsed ) ApacheRequest_parse(req);
if (GIMME == G_SCALAR) {
STRLEN n_a;
char *name = sv ? SvPV(sv, n_a) : NULL;
if (name) {
uptr = ApacheUpload_find(req->upload, name);
}
else {
uptr = req->upload;
}
if (!uptr)
XSRETURN_UNDEF;
upload_push(aTHX_ uptr);
}
else {
for (uptr = req->upload; uptr; uptr = uptr->next)
upload_push(aTHX_ uptr);
}
char *
ApacheRequest_expires(req, time_str)
Apache::Request req
char *time_str
MODULE = Apache::Request PACKAGE = Apache::Upload PREFIX = ApacheUpload_
PROTOTYPES: DISABLE
ApreqInputStream
ApacheUpload_fh(upload)
Apache::Upload upload
PREINIT:
int fd;
FILE *fp;
CODE:
fp = ApacheUpload_fh(upload);
if (fp == NULL)
XSRETURN_UNDEF;
#if PERL_REVISION == 5 && PERL_VERSION > 7
fd = PerlLIO_dup(fileno(fp));
/* XXX: user should check errno on undef returns */
if (fd < 0)
XSRETURN_UNDEF;
if ( !(RETVAL = PerlIO_fdopen(fd, "rb")) )
XSRETURN_UNDEF;
#else
if ( ( RETVAL = PerlIO_importFILE(fp,0) ) == NULL )
XSRETURN_UNDEF;
#endif
OUTPUT:
RETVAL
CLEANUP:
/* XXX: there may be a leak/segfault in here somewhere */
#if PERL_REVISION == 5 && PERL_VERSION > 7
if (ST(0) != &PL_sv_undef) {
IO *io = GvIOn((GV*)SvRV(ST(0)));
if (upload->req->parsed)
PerlIO_seek(IoIFP(io), 0, 0);
}
#else
if (ST(0) != &PL_sv_undef) {
IO *io = GvIOn((GV*)SvRV(ST(0)));
int fd = PerlIO_fileno(IoIFP(io));
PerlIO *fp;
fd = PerlLIO_dup(fd);
if (!(fp = PerlIO_fdopen(fd, "rb"))) {
PerlLIO_close(fd);
croak("fdopen failed!");
}
if (upload->req->parsed)
PerlIO_seek(fp, 0, 0);
IoIFP(io) = fp;
}
#endif
long
ApacheUpload_size(upload)
Apache::Upload upload
char *
ApacheUpload_name(upload)
Apache::Upload upload
char *
ApacheUpload_filename(upload)
Apache::Upload upload
char *
ApacheUpload_tempname(upload)
Apache::Upload upload
Apache::Upload
ApacheUpload_next(upload)
Apache::Upload upload
const char *
ApacheUpload_type(upload)
Apache::Upload upload
char *
ApacheUpload_link(upload, name)
Apache::Upload upload
char *name
CODE:
RETVAL = (link(upload->tempname, name)) ? NULL : name;
OUTPUT:
RETVAL
void
ApacheUpload_info(upload, key=NULL)
Apache::Upload upload
char *key
CODE:
if (key) {
const char *val = ApacheUpload_info(upload, key);
if (!val)
XSRETURN_UNDEF;
ST(0) = sv_2mortal(newSVpv((char *)val,0));
}
else {
ST(0) = mod_perl_tie_table(upload->info);
}