Remove deprecated API
[catagits/fcgi2.git] / perl / FCGI.PL
index f8343df..03096fc 100644 (file)
@@ -1,4 +1,5 @@
 use Config;
+use ExtUtils::MakeMaker;
 
 do 'FCGI.cfg' or die "no FCGI.cfg";
 
@@ -6,7 +7,7 @@ open OUT, ">FCGI.pm";
 
 print "Generating FCGI.pm\n";
 print OUT <<'EOP';
-# $Id: FCGI.PL,v 1.26 2001/08/22 17:20:20 skimo Exp $
+# $Id: FCGI.PL,v 1.37 2002/12/15 20:02:48 skimo Exp $
 
 package FCGI;
 
@@ -18,15 +19,17 @@ require DynaLoader;
 # 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.60';
+);
 
 EOP
 
+print OUT '$VERSION = q{'.MM->parse_version('version.pm')."};\n\n";
+
 print OUT "bootstrap FCGI;\n" unless ($pure);
 
+print OUT '$VERSION = eval $VERSION;';
+
 print OUT <<'EOP' if ($pure);
 use Symbol;
 use POSIX 'ENOTCONN';
@@ -44,38 +47,46 @@ use constant AUTHORIZER => 2;
 use constant FILTER => 3;
 
 %FCGI::rolenames = (RESPONDER, "RESPONDER",
-                     AUTHORIZER, "AUTHORIZER",
-                     FILTER, "FILTER",
-                    );
+              AUTHORIZER, "AUTHORIZER",
+              FILTER, "FILTER",
+             );
+
+# This only works on Unix; anyone familiar with Windows is welcome
+# to give a hand here
 sub IsFastCGI {
     my ($req) = @_;
     $req->{isfastcgi} =
-       (!defined getpeername shift->{listen_sock}) && $! == ENOTCONN
-       unless exists $req->{isfastcgi};
+    (!defined getpeername shift->{listen_sock}) && $! == ENOTCONN
+    unless exists $req->{isfastcgi};
     return $req->{isfastcgi};
 }
 
+sub GetEnvironment {
+    return shift->{'env'};
+}
+
 sub read_nv_len {
     my ($stream) = @_;
     my $buf;
     return undef unless read $stream, $buf, 1, 0;
     my ($len) = unpack("C", $buf);
     if ($len & 0x80) {
-       $buf = pack("C", $len & 0x7F);
-       return undef unless read $stream, $buf, 3, 1;
-       $len = unpack("N", $buf);
+    $buf = pack("C", $len & 0x7F);
+    return undef unless read $stream, $buf, 3, 1;
+    $len = unpack("N", $buf);
     }
     $len;
 }
 
 sub RequestX {
     my $self = {
-       in => shift,
-       out => shift,
-       err => shift,
-       env => shift,
-       socket => shift,
-       flags => shift,
+    in => shift,
+    out => shift,
+    err => shift,
+    env => shift,
+    socket => shift,
+    flags => shift,
+    last => 0,
     };
     open $self->{listen_sock}, "<&=0";
     bless $self, "FCGI";
@@ -87,21 +98,21 @@ sub Accept {
     my ($req) = @_;
 
     unless ($req->IsFastCGI()) {
-       return -1 if $run_once;
+        return -1 if $run_once;
 
-       $run_once = 1;
-       return 0;
+        $run_once = 1;
+        return 0;
     }
     $req->Finish();
     $req->{socket} = gensym();
-    if (!accept($req->{socket}, $req->{listen_sock})) {
-       $req->{error} = "accept";
-       return -1;
+    if ($req->{last} || !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;
+        $req->{error} = "begin request";
+        return -1;
     }
     my ($role, $flags) = unpack("nC", $body);
     $req->{role} = $role;
@@ -112,12 +123,13 @@ sub Accept {
     $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;
+    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;
@@ -155,13 +167,18 @@ sub Finish {
     my ($req) = @_;
     return unless $req->{accepted};
     if ($req->{bound}) {
-       $req->UndoBindings();
-       close ${$req->{out}};
-       close ${$req->{err}};
+        $req->UndoBindings();
+        # apparently these are harmful
+        # close ${$req->{out}};
+        # close ${$req->{err}};
     }
     $req->{accepted} = 0;
 }
 
+sub LastCall {
+    shift->{last} = 1;
+}
+
 sub DESTROY {
     shift->Finish();
 }
@@ -180,16 +197,16 @@ sub read_record {
 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;
-       }
-       $self->{buf} .= $buf;
+        my ($type, $id, $buf) = $self->read_record();
+        return undef unless defined $buf;
+        if ($type != $rtype) {
+            $self->{error} = "unexpected stream type";
+            return 0;
+        }
+        $self->{buf} .= $buf;
     }
-    my ($newbuf, $result) = (substr($self->{buf}, $len), 
-                            substr($self->{buf}, 0, $len));
+    my ($newbuf, $result) = (substr($self->{buf}, $len),
+                 substr($self->{buf}, 0, $len));
     $self->{buf} = $newbuf;
     $result;
 }
@@ -205,12 +222,19 @@ sub write {
 }
 
 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;
+    my ($self, $type, $content, $length) = @_;
+    my $offset = 0;
+    while ($length > 0) {
+        my $len = $length > 32*1024 ? 32*1024 : $length;
+        my $padlen = (8 - ($len % 8)) % 8;
+        my $templ = "CCnnCxa${len}x$padlen";
+        my $data = pack($templ,
+            VERSION_1, $type, $self->{id}, $len, $padlen,
+            substr($content, $offset, $len));
+        syswrite $self->{socket}, $data;
+        $length -= $len;
+        $offset += $len;
+    }
 }
 
 { package FCGI::Stream;
@@ -239,8 +263,9 @@ sub READ {
 sub PRINT {
     my ($stream) = shift;
     for (@_) {
-       $stream->{src}->write($stream->{type}, $_, length($_));
+        $stream->{src}->write($stream->{type}, $_, length($_));
     }
+    return 1;
 }
 
 sub CLOSE {
@@ -262,71 +287,12 @@ __END__
 *FAIL_ACCEPT_ON_INTR = sub() { 1 };
 
 sub Request(;***$*$) {
-    my @defaults = (\*STDIN, \*STDOUT, \*STDERR, \%ENV, 0, 0);
-    $_[4] = fileno($_[4]) if defined(fileno($_[4]));
+    my @defaults = (\*STDIN, \*STDOUT, \*STDERR, \%ENV, 0, FAIL_ACCEPT_ON_INTR());
+    $_[4] = fileno($_[4]) if defined($_[4]) && defined(fileno($_[4]));
     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 {
@@ -345,14 +311,14 @@ sub READLINE {
 
     $c = $stream->GETC();
     if ($/ eq '') {
-       while ($c eq "\n") { 
-           $c = $stream->GETC();
-       }
+        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 .= $c;
+        last if $c eq $l and substr($s, -$len) eq $rs;
+        $c = $stream->GETC();
     }
     $s;
 }
@@ -360,15 +326,21 @@ sub READLINE {
 sub OPEN {
     $_[0]->CLOSE;
     if (@_ == 2) {
-       return open($_[0], $_[1]);
+        return open($_[0], $_[1]);
     } else {
-       my $rc;
-       eval("$rc = open($_[0], $_[1], $_[2])");
-       die $@ if $@;
-       return $rc;
+        my $rc;
+        eval("$rc = open($_[0], $_[1], $_[2])");
+        die $@ if $@;
+        return $rc;
     }
 }
 
+# Some things (e.g. IPC::Run) use fileno to determine if a filehandle is open,
+# so we return a defined, but meaningless value. (-1 being the error return
+# value from the syscall in c, meaning it can never be a valid fd no)
+# Probably a better alternative would be to return the fcgi stream fd.
+sub FILENO { -1 }
+
 1;
 
 =pod
@@ -385,7 +357,7 @@ FCGI - Fast CGI module
     my $request = FCGI::Request();
 
     while($request->Accept() >= 0) {
-       print("Content-type: text/html\r\n\r\n", ++$count);
+        print("Content-type: text/html\r\n\r\n", ++$count);
     }
 
 =head1 DESCRIPTION
@@ -407,7 +379,7 @@ Creates a request handle. It has the following optional parameters:
 =item error perl file handle (default: \*STDERR)
 
 These filehandles will be setup to act as input/output/error
-on succesful Accept.
+on successful Accept.
 
 =item environment hash reference (default: \%ENV)
 
@@ -422,7 +394,7 @@ that should be passed. This may change in the future.
 
 You should only use your own socket if your program
 is not started by a process manager such as mod_fastcgi
-(except for the FastCgiExternalServer case) or cgi-fcgi. 
+(except for the FastCgiExternalServer case) or cgi-fcgi.
 If you use the option, you have to let your FastCGI
 server know which port (and possibly server) your program
 is listening on.
@@ -513,6 +485,14 @@ Temporarily detaches filehandles on an accepted connection.
 
 Re-attaches filehandles on an accepted connection.
 
+=item $req->LastCall()
+
+Tells the library not to accept any more requests on this handle.
+It should be safe to call this method from signal handlers.
+
+Note that this method is still experimental and everything
+about it, including its name, is subject to change.
+
 =item $env = $req->GetEnvironment()
 
 Returns the environment parameter passed to FCGI::Request.
@@ -527,6 +507,21 @@ Returns whether or not the program was run as a FastCGI.
 
 =back
 
+=HEAD1 LIMITATIONS
+
+FCGI.pm isn't Unicode aware, only characters within the range 0x00-0xFF are 
+supported. Attempts to output strings containing characters above 0xFF results
+in a exception: (F) C<Wide character in %s>.
+
+Users who wants the previous (FCGI.pm <= 0.68) incorrect behavior can disable the
+exception by using the C<bytes> pragma.
+
+    {
+        use bytes;
+        print "\x{263A}";
+    }
+
+
 =head1 AUTHOR
 
 Sven Verdoolaege <skimo@kotnet.org>