blob: abdda745f9b396469c76bed53290b06c1d4acefd [file] [log] [blame]
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 1996-2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*/
#include "mod_perl.h"
#define dHANDLE(name) GV *handle = gv_fetchpv(name, TRUE, SVt_PVIO)
#ifdef PERL_REVISION
# if ((PERL_REVISION == 5) && (PERL_VERSION >= 7))
# define TIEHANDLE_SV(handle) (SV*)GvIOp((SV*)handle)
# endif
#endif
#ifndef TIEHANDLE_SV
# define TIEHANDLE_SV(handle) (SV*)handle
#endif
#define TIEHANDLE(name,obj) \
{ \
dHANDLE(name); \
sv_unmagic(TIEHANDLE_SV(handle), 'q'); \
sv_magic(TIEHANDLE_SV(handle), obj, 'q', Nullch, 0); \
}
#if 0
#define TIED tied_handle
static int tied_handle(char *name)
{
dHANDLE(name);
/* XXX so Perl*Handler's can re-tie before PerlHandler is run?
* then they'd also be reponsible for re-tie'ing to `Apache'
* after all PerlHandlers are run, hmm must think.
*/
MAGIC *mg;
if (SvMAGICAL(handle) && (mg = mg_find((SV*)handle, 'q'))) {
char *package = HvNAME(SvSTASH((SV*)SvRV(mg->mg_obj)));
if(!strEQ(package, "Apache")) {
fprintf(stderr, "%s tied to %s\n", GvNAME(handle), package);
return TRUE;
}
}
return FALSE;
}
#else
#define TIED(name) 0
#endif
#ifdef USE_SFIO
typedef struct {
Sfdisc_t disc; /* the sfio discipline structure */
request_rec *r;
} Apache_t;
static int sfapachewrite(f, buffer, n, disc)
Sfio_t* f; /* stream involved */
char* buffer; /* buffer to write from */
int n; /* number of bytes to send */
Sfdisc_t* disc; /* discipline */
{
/* feed buffer to Apache->print */
CV *cv = GvCV(gv_fetchpv("Apache::print", FALSE, SVt_PVCV));
dSP;
ENTER;
SAVETMPS;
PUSHMARK(sp);
XPUSHs(perl_bless_request_rec(((Apache_t*)disc)->r));
XPUSHs(sv_2mortal(newSVpv(buffer,n)));
PUTBACK;
(void)(*CvXSUB(cv))(aTHXo_ cv);
FREETMPS;
LEAVE;
return n;
}
static int sfapacheread(f, buffer, bufsiz, disc)
Sfio_t* f; /* stream involved */
char* buffer; /* buffer to read into */
int bufsiz; /* number of bytes to read */
Sfdisc_t* disc; /* discipline */
{
dSP;
int count;
int nrd;
SV *sv = sv_newmortal();
request_rec *r = ((Apache_t*)disc)->r;
MP_TRACE_g(fprintf(stderr, "sfapacheread: want %d bytes\n", bufsiz));
ENTER;SAVETMPS;
PUSHMARK(sp);
XPUSHs(perl_bless_request_rec(r));
XPUSHs(sv);
XPUSHs(sv_2mortal(newSViv(bufsiz)));
PUTBACK;
count = perl_call_pv("Apache::read", G_SCALAR|G_EVAL);
SPAGAIN;
if (SvTRUE(ERRSV)) {
fprintf (stderr, "Apache::read died %s\n", SvPV(ERRSV, na));
nrd = -1;
POPs;
}
else {
char *tmpbuf = SvPV(sv, nrd);
if(count == 1) {
nrd = POPi;
}
MP_TRACE_g(fprintf(stderr, "sfapacheread: got %d \"%.*s\"\n",
nrd, nrd > 40 ? 40 : nrd, tmpbuf));
if (nrd > bufsiz) {
abort();
}
memcpy(buffer, tmpbuf, nrd);
}
PUTBACK;
FREETMPS;LEAVE;
return nrd;
}
Sfdisc_t * sfdcnewapache(request_rec *r)
{
Apache_t* disc;
if(!(disc = (Apache_t*)malloc(sizeof(Apache_t))) )
return (Sfdisc_t *)disc;
MP_TRACE_g(fprintf(stderr, "sfdcnewapache(r)\n"));
disc->disc.readf = (Sfread_f)sfapacheread;
disc->disc.writef = (Sfwrite_f)sfapachewrite;
disc->disc.seekf = (Sfseek_f)NULL;
disc->disc.exceptf = (Sfexcept_f)NULL;
disc->r = r;
return (Sfdisc_t *)disc;
}
#endif
void perl_soak_script_output(request_rec *r)
{
SV *sv = sv_newmortal();
sv_setref_pv(sv, "Apache::FakeRequest", (void*)r);
if(!perl_get_cv("Apache::FakeRequest::PRINT", FALSE))
(void)perl_eval_pv("package Apache::FakeRequest; sub PRINT {}; sub PRINTF {}", TRUE);
#ifdef USE_SFIO
sfdisc(PerlIO_stdout(), SF_POPDISC);
#endif
TIEHANDLE("STDOUT", sv);
/* we're most likely in the middle of send_cgi_header(),
* flick this switch so send_http_header() isn't called
*/
mod_perl_sent_header(r, TRUE);
}
void perl_stdout2client(request_rec *r)
{
dTHR;
#ifdef USE_SFIO
sfdisc(PerlIO_stdout(), SF_POPDISC);
sfdisc(PerlIO_stdout(), sfdcnewapache(r));
IoFLAGS(GvIOp(defoutgv)) |= IOf_FLUSH; /* $|=1 */
#else
IoFLAGS(GvIOp(defoutgv)) &= ~IOf_FLUSH; /* $|=0 */
if(TIED("STDOUT")) return;
MP_TRACE_g(fprintf(stderr, "tie *STDOUT => Apache\n"));
TIEHANDLE("STDOUT", perl_bless_request_rec(r));
#endif
}
void perl_stdin2client(request_rec *r)
{
#ifdef USE_SFIO
sfdisc(PerlIO_stdin(), SF_POPDISC);
sfdisc(PerlIO_stdin(), sfdcnewapache(r));
sfsetbuf(PerlIO_stdin(), NULL, 0);
#else
if(TIED("STDIN")) return;
MP_TRACE_g(fprintf(stderr, "tie *STDIN => Apache\n"));
TIEHANDLE("STDIN", perl_bless_request_rec(r));
#endif
}