pure perl implementation
skimo [Sun, 31 Dec 2000 21:46:58 +0000 (21:46 +0000)]
perl/FCGI.PL
perl/FCGI.XL [new file with mode: 0644]
perl/FCGI.pm [deleted file]
perl/MANIFEST
perl/Makefile.PL

index ddd32ec..e1e1103 100644 (file)
 use Config;
 
-open OUT, ">FCGI.xs";
+do 'FCGI.cfg' or die "no FCGI.cfg";
 
-print "Generating FCGI.xs for Perl version $]\n";
-#unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005) 
-unless ($] >= 5.005) {
-    for (qw(sv_undef diehook warnhook in_eval)) {
-       print OUT "#define PL_$_ $_\n" 
+open OUT, ">FCGI.pm";
+
+print "Generating FCGI.pm\n";
+print OUT <<'EOP';
+# $Id: FCGI.PL,v 1.21 2000/12/31 21:46:58 skimo Exp $
+
+package FCGI;
+
+require Exporter;
+require DynaLoader;
+
+@ISA = qw(Exporter DynaLoader);
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+@EXPORT = qw(
+       
+);
+
+$VERSION = '0.58';
+
+EOP
+
+print OUT "bootstrap FCGI;\n" unless ($pure);
+
+print OUT <<'EOP' if ($pure);
+use Symbol;
+use POSIX 'ENOTCONN';
+
+use constant VERSION_1 => 1;
+
+use constant BEGIN_REQUEST => 1;
+use constant PARAMS => 4;
+use constant FCGI_STDIN => 5;
+use constant FCGI_STDOUT => 6;
+use constant FCGI_STDERR => 7;
+
+use constant RESPONDER => 1;
+use constant AUTHORIZER => 2;
+use constant FILTER => 3;
+
+%FCGI::rolenames = (RESPONDER, "RESPONDER",
+                     AUTHORIZER, "AUTHORIZER",
+                     FILTER, "FILTER",
+                    );
+sub IsFastCGI {
+    my ($req) = @_;
+    $req->{isfastcgi} =
+       (!defined getpeername shift->{listen_sock}) && $! == ENOTCONN
+       unless exists $req->{isfastcgi};
+    return $req->{isfastcgi};
+}
+
+sub read_nv_len {
+    my ($stream) = @_;
+    my $buf;
+    return undef unless read $stream, $buf, 1, 0;
+    my ($len) = unpack("C", $buf);
+    if ($len & 0x80) {
+       return undef unless read $stream, $buf, 3, 1;
+       $len = unpack("N", $buf);
     }
+    $len;
 }
-print OUT while <DATA>;
-close OUT;
-__END__
-/* $Id: FCGI.PL,v 1.20 2000/11/14 23:15:20 skimo Exp $ */
-
-#include "EXTERN.h"
-#include "perl.h"
-#include "XSUB.h"
-
-#include "fcgi_config.h"
-#include "fcgiapp.h"
-#include "fastcgi.h"
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-
-#ifndef TRUE
-#define TRUE  (1)
-#endif
-
-#ifndef dTHX
-#define dTHX
-#endif
-
-#ifdef USE_SFIO
-typedef struct
-{
-    Sfdisc_t   disc;
-    FCGX_Stream        *stream;
-} FCGI_Disc;
-
-static ssize_t
-sffcgiread(f, buf, n, disc)
-Sfio_t*                f;      /* stream involved */
-Void_t*                buf;    /* buffer to read into */
-size_t         n;      /* number of bytes to read */
-Sfdisc_t*      disc;   /* discipline */
-{
-    return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
-}
-
-static ssize_t
-sffcgiwrite(f, buf, n, disc)
-Sfio_t*                f;      /* stream involved */
-const Void_t*  buf;    /* buffer to read into */
-size_t         n;      /* number of bytes to read */
-Sfdisc_t*      disc;   /* discipline */
-{
-    n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream);
-    FCGX_FFlush(((FCGI_Disc *)disc)->stream);
-    return n;
-}
-
-Sfdisc_t *
-sfdcnewfcgi(stream)
-       FCGX_Stream *stream;
-{
-    FCGI_Disc* disc;
-
-    New(1000,disc,1,FCGI_Disc);
-    if (!disc) return (Sfdisc_t *)disc;
-
-    disc->disc.exceptf = (Sfexcept_f)NULL;
-    disc->disc.seekf = (Sfseek_f)NULL;
-    disc->disc.readf = sffcgiread;
-    disc->disc.writef = sffcgiwrite;
-    disc->stream = stream;
-    return (Sfdisc_t *)disc;
-}
-
-Sfdisc_t *
-sfdcdelfcgi(disc)
-    Sfdisc_t*  disc;
-{
-    Safefree(disc);
+
+sub RequestX {
+    my $self = {
+       in => shift,
+       out => shift,
+       err => shift,
+       env => shift,
+       socket => shift,
+       flags => shift,
+    };
+    open $self->{listen_sock}, "<&=0";
+    bless $self, "FCGI";
+}
+
+my $run_once = 0;
+
+sub Accept {
+    my ($req) = @_;
+
+    unless ($req->IsFastCGI()) {
+       return -1 if $run_once;
+
+       $run_once = 1;
+       return 0;
+    }
+    $req->Finish();
+    $req->{socket} = gensym();
+    if (!accept($req->{socket}, $req->{listen_sock})) {
+       $req->{error} = "accept";
+       return -1;
+    }
+    my ($type, $id, $body) = $req->read_record();
+    if ($type != BEGIN_REQUEST) {
+       $req->{error} = "begin request";
+       return -1;
+    }
+    my ($role, $flags) = unpack("nC", $body);
+    $req->{role} = $role;
+    $req->{flags} = $flags;
+    $req->{id} = $id;
+
+    %{$req->{env}} = ();
+    $req->{env}{FCGI_ROLE} = $FCGI::rolenames{$req->{role}};
+    my $param = FCGI::Stream->new($req, PARAMS);
+    my ($nlen, $vlen);
+    while (defined($nlen = read_nv_len($param)) && 
+          defined($vlen = read_nv_len($param))) {
+       my ($name, $val);
+       read $param, $name, $nlen;
+       read $param, $val, $vlen;
+       $req->{env}{$name} = $val;
+    }
+    $req->Bind;
+    $req->{accepted} = 1;
+
     return 0;
 }
-#endif
-
-#if defined(USE_LOCKING) && defined(USE_THREADS)
-static perl_mutex   accept_mutex;
-#endif
-
-typedef struct FCGP_Request {
-    int                    accepted;
-    int                    bound;
-    SV*                    svin;
-    SV*                    svout;
-    SV*                    sverr;
-    GV*                    gv[3];
-    HV*                    hvEnv;
-    FCGX_Request*   requestPtr;
-#ifdef USE_SFIO
-    int                    sfcreated[3];
-    IO*                    io[3];
-#endif
-} FCGP_Request;
-
-static void FCGI_Finish(FCGP_Request* request);
-
-static int 
-FCGI_Flush(FCGP_Request* request)
-{
-    dTHX;
-
-    if(!request->bound) {
-       return;
+
+sub UndoBindings {
+    my ($req) = @_;
+    untie ${$req->{in}};
+    untie ${$req->{out}};
+    untie ${$req->{err}};
+    $req->{bound} = 0;
+}
+
+sub Bind {
+    my ($req) = @_;
+    tie ${$req->{in}}, 'FCGI::Stream', $req, FCGI_STDIN;
+    tie ${$req->{out}}, 'FCGI::Stream', $req, FCGI_STDOUT;
+    tie ${$req->{err}}, 'FCGI::Stream', $req, FCGI_STDERR;
+    $req->{bound} = 1;
+}
+
+sub Attach {
+    my ($req) = @_;
+    $req->Bind() if ($req->{accepted} && !$req->{bound});
+}
+
+sub Detach {
+    my ($req) = @_;
+    $req->UndoBindings() if ($req->{accepted} && $req->{bound});
+}
+
+sub Finish {
+    my ($req) = @_;
+    return unless $req->{accepted};
+    if ($req->{bound}) {
+       $req->UndoBindings();
+       close ${$req->{out}};
+       close ${$req->{err}};
     }
-#ifdef USE_SFIO
-    sfsync(IoOFP(GvIOp(request->gv[1])));
-    sfsync(IoOFP(GvIOp(request->gv[2])));
-#else
-    FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->svout)));
-    FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->sverr)));
-#endif
-}
-
-static void
-FCGI_UndoBinding(FCGP_Request* request)
-{
-    dTHX;
-
-#ifdef USE_SFIO
-    sfdcdelfcgi(sfdisc(IoIFP(request->io[0]), SF_POPDISC));
-    sfdcdelfcgi(sfdisc(IoOFP(request->io[1]), SF_POPDISC));
-    sfdcdelfcgi(sfdisc(IoOFP(request->io[2]), SF_POPDISC));
-#else
-    sv_unmagic((SV *)request->gv[0], 'q');
-    sv_unmagic((SV *)request->gv[1], 'q');
-    sv_unmagic((SV *)request->gv[2], 'q');
-#endif
-    request->bound = FALSE;
-}
-
-static void
-FCGI_Bind(FCGP_Request* request)
-{
-    dTHX;
-
-#ifdef USE_SFIO
-    sfdisc(IoIFP(request->io[0]), sfdcnewfcgi(request->requestPtr->in));
-    sfdisc(IoOFP(request->io[1]), sfdcnewfcgi(request->requestPtr->out));
-    sfdisc(IoOFP(request->io[2]), sfdcnewfcgi(request->requestPtr->err));
-#else
-    sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0);
-    sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0);
-    sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0);
-#endif
-    request->bound = TRUE;
-}
-
-static void
-populate_env(envp, hv)
-char **envp;
-HV *hv;
-{
-    int i;
-    char *p, *p1;
-    SV   *sv;
-    dTHX;
-
-    hv_clear(hv);
-    for(i = 0; ; i++) {
-       if((p = envp[i]) == NULL) {
-           break;
+    $req->{accepted} = 0;
+}
+
+sub DESTROY {
+    shift->Finish();
+}
+
+sub read_record {
+    my ($self) = @_;
+    my ($header, $body);
+
+    read($self->{socket}, $header, 8);
+    my ($version, $type, $id, $clen, $plen) = unpack("CCnnC", $header);
+    read($self->{socket}, $body, $clen+$plen);
+    $body = undef if $clen == 0;
+    ($type, $id, $body);
+}
+
+sub read {
+    my ($self, $rtype, $len) = @_;
+    while (length $self->{buf} < $len) {
+       my ($type, $id, $buf) = $self->read_record();
+       return undef unless defined $buf;
+       if ($type != $rtype) {
+           $self->{error} = "unexpected stream type";
+           return 0;
        }
-       p1 = strchr(p, '=');
-       assert(p1 != NULL);
-       sv = newSVpv(p1 + 1, 0);
-       /* call magic for this value ourselves */
-       hv_store(hv, p, p1 - p, sv, 0);
-       SvSETMAGIC(sv);
+       $self->{buf} .= $buf;
     }
+    my ($newbuf, $result) = (substr($self->{buf}, $len), 
+                            substr($self->{buf}, 0, $len));
+    $self->{buf} = $newbuf;
+    $result;
+}
+
+sub Flush {
+    my ($req) = @_;
+}
+
+sub write {
+    my ($self, $type, $content, $len) = @_;
+    return unless $len > 0;
+    $self->write_record($type, $content, $len);
 }
 
-static int
-FCGI_IsFastCGI(FCGP_Request* request)
-{
-    static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
+sub write_record {
+    my ($self, $type, $content, $len) = @_;
+    my $padlen = (8 - ($len % 8)) % 8;
+    my $templ = "CCnnCxa${len}x$padlen";
+    my $data = pack($templ, 
+                   VERSION_1, $type, $self->{id}, $len, $padlen, $content);
+    syswrite $self->{socket}, $data;
+}
+
+{ package FCGI::Stream;
+
+sub new {
+    my ($class, $src, $type) = @_;
+    my $handle = do { \local *FH };
+    tie($$handle, $class, $src, $type);
+    $handle;
+}
+
+sub TIEHANDLE {
+    my ($class, $src, $type) = @_;
+    bless { src => $src, type => $type }, $class;
+}
 
-    if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) {
-       if (isCGI == -1)
-           isCGI = FCGX_IsCGI();
-       return !isCGI;
+sub READ {
+    my ($stream, undef, $len, $offset) = @_;
+    my ($ref) = \$_[1];
+    my $buf = $stream->{src}->read($stream->{type}, $len);
+    return undef unless defined $buf;
+    substr($$ref, $offset, 0, $buf);
+    length $buf;
+}
+
+sub PRINT {
+    my ($stream) = shift;
+    for (@_) {
+       $stream->{src}->write($stream->{type}, $_, length($_));
     }
+}
 
-    /* A explicit socket is being used -> assume FastCGI */
-    return 1;
+sub CLOSE {
+    my ($stream) = @_;
+    $stream->{src}->write_record($stream->{type}, undef, 0);
 }
 
-static int 
-FCGI_Accept(FCGP_Request* request)
-{
-    dTHX;
+}
+
+EOP
+print OUT while <DATA>;
+close OUT;
+__END__
+
+# Preloaded methods go here.
 
-    if (!FCGI_IsFastCGI(request)) {
-       static int been_here = 0;
+# Autoload methods go after __END__, and are processed by the autosplit program.
 
-        /*
-         * Not first call to FCGI_Accept and running as CGI means
-         * application is done.
-         */
-       if (been_here)
-           return EOF;
+*FAIL_ACCEPT_ON_INTR = sub() { 1 };
+
+sub Request(;***$$$) {
+    my @defaults = (\*STDIN, \*STDOUT, \*STDERR, \%ENV, 0, 0);
+    splice @defaults,0,@_,@_;
+    RequestX(@defaults);
+}
 
-       been_here = 1;
+sub accept() {
+    warn "accept called as a method; you probably wanted to call Accept" if @_;
+    if (defined %FCGI::ENV) {
+       %ENV = %FCGI::ENV;
     } else {
-#ifdef USE_SFIO
-       int i;
-#endif
-       FCGX_Request *fcgx_req = request->requestPtr;
-        int acceptResult;
-
-       FCGI_Finish(request);
-#if defined(USE_LOCKING) && defined(USE_THREADS)
-       MUTEX_LOCK(&accept_mutex);
-#endif
-       acceptResult = FCGX_Accept_r(fcgx_req);
-#if defined(USE_LOCKING) && defined(USE_THREADS)
-       MUTEX_UNLOCK(&accept_mutex);
-#endif
-        if(acceptResult < 0) {
-            return acceptResult;
-        }
-
-       populate_env(fcgx_req->envp, request->hvEnv);
-
-#ifdef USE_SFIO
-       for (i = 0; i < 3; ++i) {
-           request->io[i] = GvIOn(request->gv[i]);
-           if (!(i == 0 ? IoIFP(request->io[i]) 
-                        : IoOFP(request->io[i]))) {
-               IoIFP(request->io[i]) = sftmp(0);
-               /*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0, 
-                                    SF_STRING | (i ? SF_WRITE : SF_READ));*/
-               if (i != 0) 
-                   IoOFP(request->io[i]) = IoIFP(request->io[i]);
-               request->sfcreated[i] = TRUE;
-           }
-       }
-#else
-       if (!request->svout) {
-           newSVrv(request->svout = newSV(0), "FCGI::Stream");
-           newSVrv(request->sverr = newSV(0), "FCGI::Stream");
-           newSVrv(request->svin = newSV(0), "FCGI::Stream");
-       }
-       sv_setiv(SvRV(request->svout), (IV) fcgx_req->out);
-       sv_setiv(SvRV(request->sverr), (IV) fcgx_req->err);
-       sv_setiv(SvRV(request->svin), (IV) fcgx_req->in);
-#endif
-       FCGI_Bind(request);
-       request->accepted = TRUE;
+       %FCGI::ENV = %ENV;
     }
-    return 0;
+    my $rc = Accept($global_request);
+    for (keys %FCGI::ENV) {
+       $ENV{$_} = $FCGI::ENV{$_} unless exists $ENV{$_};
+    }
+
+    # not SFIO
+    $SIG{__WARN__} = $warn_handler if (tied (*STDIN));
+    $SIG{__DIE__} = $die_handler if (tied (*STDIN));
+
+    return $rc;
 }
 
-static void 
-FCGI_Finish(FCGP_Request* request)
-{
-#ifdef USE_SFIO
-    int i;
-#endif
-    int was_bound;
-    dTHX;
+sub finish() {
+    warn "finish called as a method; you probably wanted to call Finish" if @_;
+    %ENV = %FCGI::ENV if (defined %FCGI::ENV);
 
-    if(!request->accepted) {
-       return;
+    # not SFIO
+    if (tied (*STDIN)) {
+       delete $SIG{__WARN__} if ($SIG{__WARN__} == $warn_handler);
+       delete $SIG{__DIE__} if ($SIG{__DIE__} == $die_handler);
     }
 
-    if (was_bound = request->bound) {
-       FCGI_UndoBinding(request);
-    }
-#ifdef USE_SFIO
-    for (i = 0; i < 3; ++i) {
-       if (request->sfcreated[i]) {
-           sfclose(IoIFP(request->io[i]));
-           IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp;
-           request->sfcreated[i] = FALSE;
-       }
-    }
-#endif
-    if (was_bound)
-       FCGX_Finish_r(request->requestPtr);
-    else
-       FCGX_Free(request->requestPtr);
-    request->accepted = FALSE;
-}
-
-static int 
-FCGI_StartFilterData(FCGP_Request* request)
-{
-    return request->requestPtr->in ? 
-           FCGX_StartFilterData(request->requestPtr->in) : -1;
-}
-
-static FCGP_Request *
-FCGI_Request(in, out, err, env, socket, flags)
-    GV*            in;
-    GV*            out;
-    GV*            err;
-    HV*            env;
-    int            socket;
-    int            flags;
-{
-    FCGX_Request* fcgx_req;
-    FCGP_Request* req;
+    Finish ($global_request);
+}
 
-    Newz(551, fcgx_req, 1, FCGX_Request);
-    FCGX_InitRequest(fcgx_req, socket, flags);
-    Newz(551, req, 1, FCGP_Request);
-    req->requestPtr = fcgx_req;
-    req->gv[0] = in;
-    req->gv[1] = out;
-    req->gv[2] = err;
-    req->hvEnv = env;
+sub flush() {
+    warn "flush called as a method; you probably wanted to call Flush" if @_;
+    Flush($global_request);
+}
+
+sub detach() {
+    warn "detach called as a method; you probably wanted to call Detach" if @_;
+    Detach($global_request);
+}
 
-    return req;
+sub attach() {
+    warn "attach called as a method; you probably wanted to call Attach" if @_;
+    Attach($global_request);
 }
 
-static void
-FCGI_Release_Request(FCGP_Request *req)
-{
-    FCGI_Finish(req);
-    Safefree(req->requestPtr);
-    Safefree(req);
+# deprecated
+sub set_exit_status {
 }
 
-static void
-FCGI_Init()
-{
-#if defined(USE_LOCKING) && defined(USE_THREADS)
-    dTHX;
+sub start_filter_data() {
+    StartFilterData($global_request);
+}
+
+$global_request = Request();
+$warn_handler = sub { print STDERR @_ };
+$die_handler = sub { print STDERR @_ unless $^S };
 
-    MUTEX_INIT(&accept_mutex);
-#endif
+package FCGI::Stream;
 
-    FCGX_Init();
+sub PRINTF {
+  shift->PRINT(sprintf(shift, @_));
 }
 
-typedef FCGX_Stream *  FCGI__Stream;
-typedef FCGP_Request * FCGI;
-typedef        GV*             GLOBREF;
-typedef        HV*             HASHREF;
+sub READLINE {
+    my $stream = shift;
+    my ($s, $c);
+    my $rs = $/ eq '' ? "\n\n" : $/;
+    my $l = substr $rs, -1;
+    my $len = length $rs;
+
+    $c = $stream->GETC();
+    if ($/ eq '') {
+       while ($c eq "\n") { 
+           $c = $stream->GETC();
+       }
+    }
+    while (defined $c) {
+       $s .= $c;
+       last if $c eq $l and substr($s, -$len) eq $rs;
+       $c = $stream->GETC();
+    }
+    $s;
+}
 
-MODULE = FCGI          PACKAGE = FCGI      PREFIX = FCGI_
+sub OPEN {
+    $_[0]->CLOSE;
+    if (@_ == 2) {
+       return open($_[0], $_[1]);
+    } else {
+       my $rc;
+       eval("$rc = open($_[0], $_[1], $_[2])");
+       die $@ if $@;
+       return $rc;
+    }
+}
 
-BOOT:
-    FCGI_Init();
+1;
 
-SV *
-RequestX(in, out, err, env, socket, flags)
-    GLOBREF in;
-    GLOBREF out;
-    GLOBREF err;
-    HASHREF env;
-    int            socket;
-    int            flags;
+=pod
 
-    PROTOTYPE: ***$$$
-    CODE:
-    RETVAL = sv_setref_pv(newSV(0), "FCGI", 
-               FCGI_Request(in, out, err, env, socket, flags));
+=head1 NAME
 
-    OUTPUT:
-    RETVAL
+FCGI - Fast CGI module
 
-int
-OpenSocket(path, backlog)
-    char* path;
-    int backlog;
+=head1 SYNOPSIS
 
-    PROTOTYPE: $$
-    CODE:
-    RETVAL = FCGX_OpenSocket(path, backlog);
-    OUTPUT:
-    RETVAL
+    use FCGI;
 
-void
-CloseSocket(socket)
-    int socket;
+    my $count = 0;
+    my $request = FCGI::Request();
 
-    PROTOTYPE: $
-    CODE:
-    close(socket);
+    while($request->Accept() >= 0) {
+       print("Content-type: text/html\r\n\r\n", ++$count);
+    }
 
-int
-FCGI_Accept(request)
+=head1 DESCRIPTION
 
-    FCGI    request;
+Functions:
 
-    PROTOTYPE: $
+=over 4
 
-void
-FCGI_Finish(request)
-    FCGI    request;
+=item FCGI::Request
 
-    PROTOTYPE: $
+Creates a request handle. It has the following optional parameters:
 
-void
-FCGI_Flush(request)
-    FCGI    request;
+=over 8
 
-    PROTOTYPE: $
+=item input perl file handle (default: \*STDIN)
 
-HV *
-GetEnvironment(request)
-    FCGI    request;
+=item output perl file handle (default: \*STDOUT)
 
-    PROTOTYPE: $
+=item error perl file handle (default: \*STDERR)
 
-    CODE:
-    RETVAL = request->hvEnv;
+These filehandles will be setup to act as input/output/error
+on succesful Accept.
 
-    OUTPUT: 
-    RETVAL
+=item environment hash reference (default: \%ENV)
 
-void
-GetHandles(request)
-    FCGI    request;
+The hash will be populated with the environment.
 
-    PROTOTYPE: $
+=item socket (default: 0)
 
-    PREINIT:
-    int            i;
+Socket to communicate with the server.
+Can be the result of the OpenSocket function.
+For the moment, it's the file descriptor of the socket
+that should be passed. This may change in the future.
 
-    PPCODE:
-    EXTEND(sp,3);
-    for (i = 0; i < 3; ++i)
-       PUSHs(sv_2mortal(newRV((SV *) request->gv[i])));
+=item flags (default: 0)
 
-int
-FCGI_IsFastCGI(request)
-    FCGI    request;
+Possible values:
 
-    PROTOTYPE: $
+=over 12
 
-void
-Detach(request)
+=item FCGI::FAIL_ACCEPT_ON_INTR
 
-    FCGI    request;
+If set, Accept will fail if interrupted.
+It not set, it will just keep on waiting.
 
-    PROTOTYPE: $
+=back
 
-    CODE:
-    if (request->accepted && request->bound)
-       FCGI_UndoBinding(request);
+=back
 
-void
-Attach(request)
+Example usage:
+    my $req = FCGI::Request;
 
-    FCGI    request;
+or:
+    my %env;
+    my $in = new IO::Handle;
+    my $out = new IO::Handle;
+    my $err = new IO::Handle;
+    my $req = FCGI::Request($in, $out, $err, \%env);
 
-    PROTOTYPE: $
+=item FCGI::OpenSocket(path, backlog)
 
-    CODE:
-    if (request->accepted && !request->bound)
-       FCGI_Bind(request);
+Creates a socket suitable to use as an argument to Request.
 
+=over 8
 
-int
-FCGI_StartFilterData(request)
+=item path
 
-    FCGI    request;
+Pathname of socket or colon followed by local tcp port.
 
-    PROTOTYPE: $
+=item backlog
 
-void
-DESTROY(request)
-    FCGI    request;
+Maximum length of the queue of pending connections.
+If a connection
+request arrives with the queue full the client may receive
+an  error  with  an  indication of ECONNREFUSED.
 
-    CODE:
-    FCGI_Release_Request(request);
+=back
 
+=item FCGI::CloseSocket(socket)
 
+Close a socket opened with OpenSocket.
 
-MODULE = FCGI          PACKAGE = FCGI::Stream
+=item $req->Accept()
 
-#ifndef USE_SFIO
+Accepts a connection on $req, attaching the filehandles and
+populating the environment hash.
+Returns 0 on success.
+If a connection has been accepted before, the old
+one will be finished first.
 
-void
-PRINT(stream, ...)
-       FCGI::Stream    stream;
+Note that unlike with the old interface, no die and warn
+handlers are installed by default. This means that if
+you are not running an sfio enabled perl, any warn or
+die message will not end up in the server's log by default.
+It is advised you set up die and warn handlers yourself.
+FCGI.pm contains an example of die and warn handlers.
 
-       PREINIT:
-       int     n;
+=item $req->Finish()
 
-       CODE:
-       for (n = 1; n < items; ++n) {
-            STRLEN len;
-            register char *tmps = (char *)SvPV(ST(n),len);
-            FCGX_PutStr(tmps, len, stream);
-       }
-       if (SvTRUEx(perl_get_sv("|", FALSE))) 
-           FCGX_FFlush(stream);
-
-int
-WRITE(stream, bufsv, len, ...)
-       FCGI::Stream    stream;
-       SV *    bufsv;
-       int     len;
-
-       PREINIT:
-       int     offset;
-       char *  buf;
-       STRLEN  blen;
-       int     n;
-
-       CODE:
-       offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
-       buf = SvPV(bufsv, blen);
-       if (offset < 0) offset += blen;
-       if (len > blen - offset)
-           len = blen - offset;
-       if (offset < 0 || offset >= blen ||
-               (n = FCGX_PutStr(buf+offset, len, stream)) < 0) 
-           ST(0) = &PL_sv_undef;
-       else {
-           ST(0) = sv_newmortal();
-           sv_setpvf(ST(0), "%c", n);
-       }
+Finishes accepted connection.
+Also detaches filehandles.
+
+=item $req->Flush()
+
+Flushes accepted connection.
+
+=item $req->Detach()
+
+Temporarily detaches filehandles on an accepted connection.
 
-int
-READ(stream, bufsv, len, ...)
-       FCGI::Stream    stream;
-       SV *    bufsv;
-       int     len;
-
-       PREINIT:
-       int     offset;
-       char *  buf;
-
-       CODE:
-       offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
-       if (! SvOK(bufsv))
-           sv_setpvn(bufsv, "", 0);
-       buf = SvGROW(bufsv, len+offset+1);
-       len = FCGX_GetStr(buf+offset, len, stream);
-       SvCUR_set(bufsv, len+offset);
-       *SvEND(bufsv) = '\0';
-       (void)SvPOK_only(bufsv);
-       SvSETMAGIC(bufsv);
-       RETVAL = len;
-
-       OUTPUT:
-       RETVAL
-
-SV *
-GETC(stream)
-       FCGI::Stream    stream;
-
-       PREINIT:
-       int     retval;
-
-       CODE:
-       if ((retval = FCGX_GetChar(stream)) != -1) {
-           ST(0) = sv_newmortal();
-           sv_setpvf(ST(0), "%c", retval);
-       } else ST(0) = &PL_sv_undef;
-
-bool
-CLOSE(stream)
-       FCGI::Stream    stream;
-
-#      ALIAS:
-#      DESTROY = 1
-
-       CODE:
-       RETVAL = FCGX_FClose(stream) != -1;
-
-       OUTPUT:
-       RETVAL
-
-#endif
+=item $req->Attach()
+
+Re-attaches filehandles on an accepted connection.
+
+=item $env = $req->GetEnvironment()
+
+Returns the environment parameter passed to FCGI::Request.
+
+=item ($in, $out, $err) = $req->GetHandles()
+
+Returns the file handle parameters passed to FCGI::Request.
+
+=item $isfcgi = $req->IsFastCGI()
+
+Returns whether or not the program was run as a FastCGI.
+
+=back
+
+=head1 AUTHOR
+
+Sven Verdoolaege <skimo@kotnet.org>
+
+=cut
+
+__END__
diff --git a/perl/FCGI.XL b/perl/FCGI.XL
new file mode 100644 (file)
index 0000000..5fc9fc5
--- /dev/null
@@ -0,0 +1,585 @@
+use Config;
+
+open OUT, ">FCGI.xs";
+
+print "Generating FCGI.xs for Perl version $]\n";
+#unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005) 
+unless ($] >= 5.005) {
+    for (qw(sv_undef diehook warnhook in_eval)) {
+       print OUT "#define PL_$_ $_\n" 
+    }
+}
+print OUT while <DATA>;
+close OUT;
+__END__
+/* $Id: FCGI.XL,v 1.1 2000/12/31 21:46:58 skimo Exp $ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include "fcgi_config.h"
+#include "fcgiapp.h"
+#include "fastcgi.h"
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE  (1)
+#endif
+
+#ifndef dTHX
+#define dTHX
+#endif
+
+#ifdef USE_SFIO
+typedef struct
+{
+    Sfdisc_t   disc;
+    FCGX_Stream        *stream;
+} FCGI_Disc;
+
+static ssize_t
+sffcgiread(f, buf, n, disc)
+Sfio_t*                f;      /* stream involved */
+Void_t*                buf;    /* buffer to read into */
+size_t         n;      /* number of bytes to read */
+Sfdisc_t*      disc;   /* discipline */
+{
+    return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
+}
+
+static ssize_t
+sffcgiwrite(f, buf, n, disc)
+Sfio_t*                f;      /* stream involved */
+const Void_t*  buf;    /* buffer to read into */
+size_t         n;      /* number of bytes to read */
+Sfdisc_t*      disc;   /* discipline */
+{
+    n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream);
+    FCGX_FFlush(((FCGI_Disc *)disc)->stream);
+    return n;
+}
+
+Sfdisc_t *
+sfdcnewfcgi(stream)
+       FCGX_Stream *stream;
+{
+    FCGI_Disc* disc;
+
+    New(1000,disc,1,FCGI_Disc);
+    if (!disc) return (Sfdisc_t *)disc;
+
+    disc->disc.exceptf = (Sfexcept_f)NULL;
+    disc->disc.seekf = (Sfseek_f)NULL;
+    disc->disc.readf = sffcgiread;
+    disc->disc.writef = sffcgiwrite;
+    disc->stream = stream;
+    return (Sfdisc_t *)disc;
+}
+
+Sfdisc_t *
+sfdcdelfcgi(disc)
+    Sfdisc_t*  disc;
+{
+    Safefree(disc);
+    return 0;
+}
+#endif
+
+#if defined(USE_LOCKING) && defined(USE_THREADS)
+static perl_mutex   accept_mutex;
+#endif
+
+typedef struct FCGP_Request {
+    int                    accepted;
+    int                    bound;
+    SV*                    svin;
+    SV*                    svout;
+    SV*                    sverr;
+    GV*                    gv[3];
+    HV*                    hvEnv;
+    FCGX_Request*   requestPtr;
+#ifdef USE_SFIO
+    int                    sfcreated[3];
+    IO*                    io[3];
+#endif
+} FCGP_Request;
+
+static void FCGI_Finish(FCGP_Request* request);
+
+static int 
+FCGI_Flush(FCGP_Request* request)
+{
+    dTHX;
+
+    if(!request->bound) {
+       return;
+    }
+#ifdef USE_SFIO
+    sfsync(IoOFP(GvIOp(request->gv[1])));
+    sfsync(IoOFP(GvIOp(request->gv[2])));
+#else
+    FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->svout)));
+    FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->sverr)));
+#endif
+}
+
+static void
+FCGI_UndoBinding(FCGP_Request* request)
+{
+    dTHX;
+
+#ifdef USE_SFIO
+    sfdcdelfcgi(sfdisc(IoIFP(request->io[0]), SF_POPDISC));
+    sfdcdelfcgi(sfdisc(IoOFP(request->io[1]), SF_POPDISC));
+    sfdcdelfcgi(sfdisc(IoOFP(request->io[2]), SF_POPDISC));
+#else
+    sv_unmagic((SV *)request->gv[0], 'q');
+    sv_unmagic((SV *)request->gv[1], 'q');
+    sv_unmagic((SV *)request->gv[2], 'q');
+#endif
+    request->bound = FALSE;
+}
+
+static void
+FCGI_Bind(FCGP_Request* request)
+{
+    dTHX;
+
+#ifdef USE_SFIO
+    sfdisc(IoIFP(request->io[0]), sfdcnewfcgi(request->requestPtr->in));
+    sfdisc(IoOFP(request->io[1]), sfdcnewfcgi(request->requestPtr->out));
+    sfdisc(IoOFP(request->io[2]), sfdcnewfcgi(request->requestPtr->err));
+#else
+    sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0);
+    sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0);
+    sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0);
+#endif
+    request->bound = TRUE;
+}
+
+static void
+populate_env(envp, hv)
+char **envp;
+HV *hv;
+{
+    int i;
+    char *p, *p1;
+    SV   *sv;
+    dTHX;
+
+    hv_clear(hv);
+    for(i = 0; ; i++) {
+       if((p = envp[i]) == NULL) {
+           break;
+       }
+       p1 = strchr(p, '=');
+       assert(p1 != NULL);
+       sv = newSVpv(p1 + 1, 0);
+       /* call magic for this value ourselves */
+       hv_store(hv, p, p1 - p, sv, 0);
+       SvSETMAGIC(sv);
+    }
+}
+
+static int
+FCGI_IsFastCGI(FCGP_Request* request)
+{
+    static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
+
+    if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) {
+       if (isCGI == -1)
+           isCGI = FCGX_IsCGI();
+       return !isCGI;
+    }
+
+    /* A explicit socket is being used -> assume FastCGI */
+    return 1;
+}
+
+static int 
+FCGI_Accept(FCGP_Request* request)
+{
+    dTHX;
+
+    if (!FCGI_IsFastCGI(request)) {
+       static int been_here = 0;
+
+        /*
+         * Not first call to FCGI_Accept and running as CGI means
+         * application is done.
+         */
+       if (been_here)
+           return EOF;
+
+       been_here = 1;
+    } else {
+#ifdef USE_SFIO
+       int i;
+#endif
+       FCGX_Request *fcgx_req = request->requestPtr;
+        int acceptResult;
+
+       FCGI_Finish(request);
+#if defined(USE_LOCKING) && defined(USE_THREADS)
+       MUTEX_LOCK(&accept_mutex);
+#endif
+       acceptResult = FCGX_Accept_r(fcgx_req);
+#if defined(USE_LOCKING) && defined(USE_THREADS)
+       MUTEX_UNLOCK(&accept_mutex);
+#endif
+        if(acceptResult < 0) {
+            return acceptResult;
+        }
+
+       populate_env(fcgx_req->envp, request->hvEnv);
+
+#ifdef USE_SFIO
+       for (i = 0; i < 3; ++i) {
+           request->io[i] = GvIOn(request->gv[i]);
+           if (!(i == 0 ? IoIFP(request->io[i]) 
+                        : IoOFP(request->io[i]))) {
+               IoIFP(request->io[i]) = sftmp(0);
+               /*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0, 
+                                    SF_STRING | (i ? SF_WRITE : SF_READ));*/
+               if (i != 0) 
+                   IoOFP(request->io[i]) = IoIFP(request->io[i]);
+               request->sfcreated[i] = TRUE;
+           }
+       }
+#else
+       if (!request->svout) {
+           newSVrv(request->svout = newSV(0), "FCGI::Stream");
+           newSVrv(request->sverr = newSV(0), "FCGI::Stream");
+           newSVrv(request->svin = newSV(0), "FCGI::Stream");
+       }
+       sv_setiv(SvRV(request->svout), (IV) fcgx_req->out);
+       sv_setiv(SvRV(request->sverr), (IV) fcgx_req->err);
+       sv_setiv(SvRV(request->svin), (IV) fcgx_req->in);
+#endif
+       FCGI_Bind(request);
+       request->accepted = TRUE;
+    }
+    return 0;
+}
+
+static void 
+FCGI_Finish(FCGP_Request* request)
+{
+#ifdef USE_SFIO
+    int i;
+#endif
+    int was_bound;
+    dTHX;
+
+    if(!request->accepted) {
+       return;
+    }
+
+    if (was_bound = request->bound) {
+       FCGI_UndoBinding(request);
+    }
+#ifdef USE_SFIO
+    for (i = 0; i < 3; ++i) {
+       if (request->sfcreated[i]) {
+           sfclose(IoIFP(request->io[i]));
+           IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp;
+           request->sfcreated[i] = FALSE;
+       }
+    }
+#endif
+    if (was_bound)
+       FCGX_Finish_r(request->requestPtr);
+    else
+       FCGX_Free(request->requestPtr);
+    request->accepted = FALSE;
+}
+
+static int 
+FCGI_StartFilterData(FCGP_Request* request)
+{
+    return request->requestPtr->in ? 
+           FCGX_StartFilterData(request->requestPtr->in) : -1;
+}
+
+static FCGP_Request *
+FCGI_Request(in, out, err, env, socket, flags)
+    GV*            in;
+    GV*            out;
+    GV*            err;
+    HV*            env;
+    int            socket;
+    int            flags;
+{
+    FCGX_Request* fcgx_req;
+    FCGP_Request* req;
+
+    Newz(551, fcgx_req, 1, FCGX_Request);
+    FCGX_InitRequest(fcgx_req, socket, flags);
+    Newz(551, req, 1, FCGP_Request);
+    req->requestPtr = fcgx_req;
+    req->gv[0] = in;
+    req->gv[1] = out;
+    req->gv[2] = err;
+    req->hvEnv = env;
+
+    return req;
+}
+
+static void
+FCGI_Release_Request(FCGP_Request *req)
+{
+    FCGI_Finish(req);
+    Safefree(req->requestPtr);
+    Safefree(req);
+}
+
+static void
+FCGI_Init()
+{
+#if defined(USE_LOCKING) && defined(USE_THREADS)
+    dTHX;
+
+    MUTEX_INIT(&accept_mutex);
+#endif
+
+    FCGX_Init();
+}
+
+typedef FCGX_Stream *  FCGI__Stream;
+typedef FCGP_Request * FCGI;
+typedef        GV*             GLOBREF;
+typedef        HV*             HASHREF;
+
+MODULE = FCGI          PACKAGE = FCGI      PREFIX = FCGI_
+
+BOOT:
+    FCGI_Init();
+
+SV *
+RequestX(in, out, err, env, socket, flags)
+    GLOBREF in;
+    GLOBREF out;
+    GLOBREF err;
+    HASHREF env;
+    int            socket;
+    int            flags;
+
+    PROTOTYPE: ***$$$
+    CODE:
+    RETVAL = sv_setref_pv(newSV(0), "FCGI", 
+               FCGI_Request(in, out, err, env, socket, flags));
+
+    OUTPUT:
+    RETVAL
+
+int
+OpenSocket(path, backlog)
+    char* path;
+    int backlog;
+
+    PROTOTYPE: $$
+    CODE:
+    RETVAL = FCGX_OpenSocket(path, backlog);
+    OUTPUT:
+    RETVAL
+
+void
+CloseSocket(socket)
+    int socket;
+
+    PROTOTYPE: $
+    CODE:
+    close(socket);
+
+int
+FCGI_Accept(request)
+
+    FCGI    request;
+
+    PROTOTYPE: $
+
+void
+FCGI_Finish(request)
+    FCGI    request;
+
+    PROTOTYPE: $
+
+void
+FCGI_Flush(request)
+    FCGI    request;
+
+    PROTOTYPE: $
+
+HV *
+GetEnvironment(request)
+    FCGI    request;
+
+    PROTOTYPE: $
+
+    CODE:
+    RETVAL = request->hvEnv;
+
+    OUTPUT: 
+    RETVAL
+
+void
+GetHandles(request)
+    FCGI    request;
+
+    PROTOTYPE: $
+
+    PREINIT:
+    int            i;
+
+    PPCODE:
+    EXTEND(sp,3);
+    for (i = 0; i < 3; ++i)
+       PUSHs(sv_2mortal(newRV((SV *) request->gv[i])));
+
+int
+FCGI_IsFastCGI(request)
+    FCGI    request;
+
+    PROTOTYPE: $
+
+void
+Detach(request)
+
+    FCGI    request;
+
+    PROTOTYPE: $
+
+    CODE:
+    if (request->accepted && request->bound)
+       FCGI_UndoBinding(request);
+
+void
+Attach(request)
+
+    FCGI    request;
+
+    PROTOTYPE: $
+
+    CODE:
+    if (request->accepted && !request->bound)
+       FCGI_Bind(request);
+
+
+int
+FCGI_StartFilterData(request)
+
+    FCGI    request;
+
+    PROTOTYPE: $
+
+void
+DESTROY(request)
+    FCGI    request;
+
+    CODE:
+    FCGI_Release_Request(request);
+
+
+
+MODULE = FCGI          PACKAGE = FCGI::Stream
+
+#ifndef USE_SFIO
+
+void
+PRINT(stream, ...)
+       FCGI::Stream    stream;
+
+       PREINIT:
+       int     n;
+
+       CODE:
+       for (n = 1; n < items; ++n) {
+            STRLEN len;
+            register char *tmps = (char *)SvPV(ST(n),len);
+            FCGX_PutStr(tmps, len, stream);
+       }
+       if (SvTRUEx(perl_get_sv("|", FALSE))) 
+           FCGX_FFlush(stream);
+
+int
+WRITE(stream, bufsv, len, ...)
+       FCGI::Stream    stream;
+       SV *    bufsv;
+       int     len;
+
+       PREINIT:
+       int     offset;
+       char *  buf;
+       STRLEN  blen;
+       int     n;
+
+       CODE:
+       offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
+       buf = SvPV(bufsv, blen);
+       if (offset < 0) offset += blen;
+       if (len > blen - offset)
+           len = blen - offset;
+       if (offset < 0 || offset >= blen ||
+               (n = FCGX_PutStr(buf+offset, len, stream)) < 0) 
+           ST(0) = &PL_sv_undef;
+       else {
+           ST(0) = sv_newmortal();
+           sv_setpvf(ST(0), "%c", n);
+       }
+
+int
+READ(stream, bufsv, len, ...)
+       FCGI::Stream    stream;
+       SV *    bufsv;
+       int     len;
+
+       PREINIT:
+       int     offset;
+       char *  buf;
+
+       CODE:
+       offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
+       if (! SvOK(bufsv))
+           sv_setpvn(bufsv, "", 0);
+       buf = SvGROW(bufsv, len+offset+1);
+       len = FCGX_GetStr(buf+offset, len, stream);
+       SvCUR_set(bufsv, len+offset);
+       *SvEND(bufsv) = '\0';
+       (void)SvPOK_only(bufsv);
+       SvSETMAGIC(bufsv);
+       RETVAL = len;
+
+       OUTPUT:
+       RETVAL
+
+SV *
+GETC(stream)
+       FCGI::Stream    stream;
+
+       PREINIT:
+       int     retval;
+
+       CODE:
+       if ((retval = FCGX_GetChar(stream)) != -1) {
+           ST(0) = sv_newmortal();
+           sv_setpvf(ST(0), "%c", retval);
+       } else ST(0) = &PL_sv_undef;
+
+bool
+CLOSE(stream)
+       FCGI::Stream    stream;
+
+#      ALIAS:
+#      DESTROY = 1
+
+       CODE:
+       RETVAL = FCGX_FClose(stream) != -1;
+
+       OUTPUT:
+       RETVAL
+
+#endif
diff --git a/perl/FCGI.pm b/perl/FCGI.pm
deleted file mode 100644 (file)
index d783590..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-# $Id: FCGI.pm,v 1.18 2000/11/14 23:15:20 skimo Exp $
-
-package FCGI;
-
-require Exporter;
-require DynaLoader;
-
-@ISA = qw(Exporter DynaLoader);
-# Items to export into callers namespace by default. Note: do not export
-# names by default without a very good reason. Use EXPORT_OK instead.
-# Do not simply export all your public functions/methods/constants.
-@EXPORT = qw(
-       
-);
-
-$VERSION = '0.58';
-
-bootstrap FCGI;
-
-# Preloaded methods go here.
-
-# Autoload methods go after __END__, and are processed by the autosplit program.
-
-*FAIL_ACCEPT_ON_INTR = sub() { 1 };
-
-sub Request(;***$$$) {
-    my @defaults = (\*STDIN, \*STDOUT, \*STDERR, \%ENV, 0, 0);
-    splice @defaults,0,@_,@_;
-    RequestX(@defaults);
-}
-
-sub accept() {
-    warn "accept called as a method; you probably wanted to call Accept" if @_;
-    if (defined %FCGI::ENV) {
-       %ENV = %FCGI::ENV;
-    } else {
-       %FCGI::ENV = %ENV;
-    }
-    my $rc = Accept($global_request);
-    for (keys %FCGI::ENV) {
-       $ENV{$_} = $FCGI::ENV{$_} unless exists $ENV{$_};
-    }
-
-    # not SFIO
-    $SIG{__WARN__} = $warn_handler if (tied (*STDIN));
-    $SIG{__DIE__} = $die_handler if (tied (*STDIN));
-
-    return $rc;
-}
-
-sub finish() {
-    warn "finish called as a method; you probably wanted to call Finish" if @_;
-    %ENV = %FCGI::ENV if (defined %FCGI::ENV);
-
-    # not SFIO
-    if (tied (*STDIN)) {
-       delete $SIG{__WARN__} if ($SIG{__WARN__} == $warn_handler);
-       delete $SIG{__DIE__} if ($SIG{__DIE__} == $die_handler);
-    }
-
-    Finish ($global_request);
-}
-
-sub flush() {
-    warn "flush called as a method; you probably wanted to call Flush" if @_;
-    Flush($global_request);
-}
-
-sub detach() {
-    warn "detach called as a method; you probably wanted to call Detach" if @_;
-    Detach($global_request);
-}
-
-sub attach() {
-    warn "attach called as a method; you probably wanted to call Attach" if @_;
-    Attach($global_request);
-}
-
-# deprecated
-sub set_exit_status {
-}
-
-sub start_filter_data() {
-    StartFilterData($global_request);
-}
-
-$global_request = Request();
-$warn_handler = sub { print STDERR @_ };
-$die_handler = sub { print STDERR @_ unless $^S };
-
-package FCGI::Stream;
-
-sub PRINTF {
-  shift->PRINT(sprintf(shift, @_));
-}
-
-sub READLINE {
-    my $stream = shift;
-    my ($s, $c);
-    my $rs = $/ eq '' ? "\n\n" : $/;
-    my $l = substr $rs, -1;
-    my $len = length $rs;
-
-    $c = $stream->GETC();
-    if ($/ eq '') {
-       while ($c eq "\n") { 
-           $c = $stream->GETC();
-       }
-    }
-    while (defined $c) {
-       $s .= $c;
-       last if $c eq $l and substr($s, -$len) eq $rs;
-       $c = $stream->GETC();
-    }
-    $s;
-}
-
-sub OPEN {
-    $_[0]->CLOSE;
-    if (@_ == 2) {
-       return open($_[0], $_[1]);
-    } else {
-       my $rc;
-       eval("$rc = open($_[0], $_[1], $_[2])");
-       die $@ if $@;
-       return $rc;
-    }
-}
-
-1;
-
-=pod
-
-=head1 NAME
-
-FCGI - Fast CGI module
-
-=head1 SYNOPSIS
-
-    use FCGI;
-
-    my $count = 0;
-    my $request = FCGI::Request();
-
-    while($request->Accept() >= 0) {
-       print("Content-type: text/html\r\n\r\n", ++$count);
-    }
-
-=head1 DESCRIPTION
-
-Functions:
-
-=over 4
-
-=item FCGI::Request
-
-Creates a request handle. It has the following optional parameters:
-
-=over 8
-
-=item input perl file handle (default: \*STDIN)
-
-=item output perl file handle (default: \*STDOUT)
-
-=item error perl file handle (default: \*STDERR)
-
-These filehandles will be setup to act as input/output/error
-on succesful Accept.
-
-=item environment hash reference (default: \%ENV)
-
-The hash will be populated with the environment.
-
-=item socket (default: 0)
-
-Socket to communicate with the server.
-Can be the result of the OpenSocket function.
-For the moment, it's the file descriptor of the socket
-that should be passed. This may change in the future.
-
-=item flags (default: 0)
-
-Possible values:
-
-=over 12
-
-=item FCGI::FAIL_ACCEPT_ON_INTR
-
-If set, Accept will fail if interrupted.
-It not set, it will just keep on waiting.
-
-=back
-
-=back
-
-Example usage:
-    my $req = FCGI::Request;
-
-or:
-    my %env;
-    my $in = new IO::Handle;
-    my $out = new IO::Handle;
-    my $err = new IO::Handle;
-    my $req = FCGI::Request($in, $out, $err, \%env);
-
-=item FCGI::OpenSocket(path, backlog)
-
-Creates a socket suitable to use as an argument to Request.
-
-=over 8
-
-=item path
-
-Pathname of socket or colon followed by local tcp port.
-
-=item backlog
-
-Maximum length of the queue of pending connections.
-If a connection
-request arrives with the queue full the client may receive
-an  error  with  an  indication of ECONNREFUSED.
-
-=back
-
-=item FCGI::CloseSocket(socket)
-
-Close a socket opened with OpenSocket.
-
-=item $req->Accept()
-
-Accepts a connection on $req, attaching the filehandles and
-populating the environment hash.
-Returns 0 on success.
-If a connection has been accepted before, the old
-one will be finished first.
-
-Note that unlike with the old interface, no die and warn
-handlers are installed by default. This means that if
-you are not running an sfio enabled perl, any warn or
-die message will not end up in the server's log by default.
-It is advised you set up die and warn handlers yourself.
-FCGI.pm contains an example of die and warn handlers.
-
-=item $req->Finish()
-
-Finishes accepted connection.
-Also detaches filehandles.
-
-=item $req->Flush()
-
-Flushes accepted connection.
-
-=item $req->Detach()
-
-Temporarily detaches filehandles on an accepted connection.
-
-=item $req->Attach()
-
-Re-attaches filehandles on an accepted connection.
-
-=item $env = $req->GetEnvironment()
-
-Returns the environment parameter passed to FCGI::Request.
-
-=item ($in, $out, $err) = $req->GetHandles()
-
-Returns the file handle parameters passed to FCGI::Request.
-
-=item $isfcgi = $req->IsFastCGI()
-
-Returns whether or not the program was run as a FastCGI.
-
-=back
-
-=head1 AUTHOR
-
-Sven Verdoolaege <skimo@kotnet.org>
-
-=cut
-
-__END__
index ad3852a..f6f7af3 100644 (file)
@@ -1,6 +1,6 @@
 ChangeLog
 FCGI.PL
-FCGI.pm
+FCGI.XL
 MANIFEST
 Makefile.PL
 README
index 9f086f2..95b9985 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile.PL,v 1.7 2000/12/11 22:00:36 skimo Exp $
+# $Id: Makefile.PL,v 1.8 2000/12/31 21:46:59 skimo Exp $
 
 use ExtUtils::MakeMaker;
 use IO::File;
@@ -12,6 +12,13 @@ use Cwd 'cwd';
 @dist2 = qw(fcgiapp.c os_unix.c os_win32.c);
 @dist3 = (@h1, qw(fcgi_config.h.in fcgi_config_x86.h));
 
+$pure = 
+    (prompt("Do you want to use the pure perl implementation", "no") =~ /^y/) 
+    ? "1" : "0";
+open(CFG,">FCGI.cfg");
+print CFG "\$pure = $pure;1;\n";
+close CFG;
+
 $devkit = cwd() . "/..";
 
 if (-d "$devkit/libfcgi/" 
@@ -55,15 +62,25 @@ push(@extras,
     ABSTRACT => 'Fast CGI module',
     AUTHOR   => 'Sven Verdoolaege (skimo@kotnet.org)')
         if ($ExtUtils::MakeMaker::VERSION >= 5.4301); 
+
+$plfiles = { 'echo.PL' => 'echo.fpl', 
+            'remote.PL' => 'remote.fpl',
+            'threaded.PL' => 'threaded.fpl',
+            'FCGI.PL' => 'FCGI.pm',
+          };
+$plfiles->{'FCGI.XL'} = 'FCGI.xs' unless $pure;
+unless ($pure) {
+    push @extras,
+       'LIBS'  => [ @libs ],
+       'OBJECT'        => "@o",
+       'INC'   => $inc;
+}
         
 # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 # the contents of the Makefile that is written.
-WriteMakefile(
+$mm = MM->new({
     'NAME'             => 'FCGI',
-    'VERSION_FROM'     => 'FCGI.pm',
-    'LIBS'             => [ @libs ],
-    'OBJECT'   => "@o",
-    'INC'              => $inc,
+    'VERSION_FROM'     => 'FCGI.PL',
     'dist'             => { 'COMPRESS' => 'gzip -9f', 
                             'SUFFIX' => 'gz',
                             'PREOP' => '$(CP) '.join(' ',
@@ -76,14 +93,15 @@ WriteMakefile(
                              'POSTOP' => 
                                '$(MV) MANIFEST.old MANIFEST',
                            },
-    'clean'            => { FILES => 'config.cache fcgi_config.h' },
-    'PL_FILES' => { 'echo.PL' => 'echo.fpl', 
-                    'remote.PL' => 'remote.fpl',
-                    'threaded.PL' => 'threaded.fpl',
-                    'FCGI.PL' => 'FCGI.xs',
-                  },
+    'clean'            => { FILES => 'config.cache fcgi_config.h FCGI.pm' . 
+                                     ' FCGI.xs FCGI.c FCGI.cfg' },
+    'PL_FILES'         => $plfiles,
+    PM                 => {'FCGI.pm' => '$(INST_ARCHLIBDIR)/FCGI.pm'},
     @extras,
-);
+});
+# don't install oldinterface pod
+delete $mm->{MAN3PODS}{oldinterface.pod};
+$mm->flush;
 
 exit if -f 'fcgi_config.h' or $prefix;