Remove deprecated API
[catagits/fcgi2.git] / perl / FCGI.PL
CommitLineData
1b64d24d 1use Config;
fa01dc1c 2use ExtUtils::MakeMaker;
1b64d24d 3
0833402a 4do 'FCGI.cfg' or die "no FCGI.cfg";
1b64d24d 5
0833402a 6open OUT, ">FCGI.pm";
7
8print "Generating FCGI.pm\n";
9print OUT <<'EOP';
9aa25e66 10# $Id: FCGI.PL,v 1.37 2002/12/15 20:02:48 skimo Exp $
0833402a 11
12package FCGI;
13
14require Exporter;
15require DynaLoader;
16
17@ISA = qw(Exporter DynaLoader);
18# Items to export into callers namespace by default. Note: do not export
19# names by default without a very good reason. Use EXPORT_OK instead.
20# Do not simply export all your public functions/methods/constants.
21@EXPORT = qw(
562f0c66 22
0833402a 23);
24
0833402a 25EOP
26
21b4f5ec 27print OUT '$VERSION = q{'.MM->parse_version('version.pm')."};\n\n";
4945bfbe 28
0833402a 29print OUT "bootstrap FCGI;\n" unless ($pure);
30
21b4f5ec 31print OUT '$VERSION = eval $VERSION;';
32
0833402a 33print OUT <<'EOP' if ($pure);
34use Symbol;
35use POSIX 'ENOTCONN';
36
37use constant VERSION_1 => 1;
38
39use constant BEGIN_REQUEST => 1;
40use constant PARAMS => 4;
41use constant FCGI_STDIN => 5;
42use constant FCGI_STDOUT => 6;
43use constant FCGI_STDERR => 7;
44
45use constant RESPONDER => 1;
46use constant AUTHORIZER => 2;
47use constant FILTER => 3;
48
49%FCGI::rolenames = (RESPONDER, "RESPONDER",
8d7b81b0 50 AUTHORIZER, "AUTHORIZER",
51 FILTER, "FILTER",
52 );
ef8432ef 53
54# This only works on Unix; anyone familiar with Windows is welcome
55# to give a hand here
0833402a 56sub IsFastCGI {
57 my ($req) = @_;
58 $req->{isfastcgi} =
8d7b81b0 59 (!defined getpeername shift->{listen_sock}) && $! == ENOTCONN
60 unless exists $req->{isfastcgi};
0833402a 61 return $req->{isfastcgi};
62}
63
ef8432ef 64sub GetEnvironment {
65 return shift->{'env'};
66}
67
0833402a 68sub read_nv_len {
69 my ($stream) = @_;
70 my $buf;
71 return undef unless read $stream, $buf, 1, 0;
72 my ($len) = unpack("C", $buf);
73 if ($len & 0x80) {
8d7b81b0 74 $buf = pack("C", $len & 0x7F);
75 return undef unless read $stream, $buf, 3, 1;
76 $len = unpack("N", $buf);
1b64d24d 77 }
0833402a 78 $len;
1b64d24d 79}
0833402a 80
81sub RequestX {
82 my $self = {
8d7b81b0 83 in => shift,
84 out => shift,
85 err => shift,
86 env => shift,
87 socket => shift,
88 flags => shift,
89 last => 0,
0833402a 90 };
91 open $self->{listen_sock}, "<&=0";
92 bless $self, "FCGI";
93}
94
95my $run_once = 0;
96
97sub Accept {
98 my ($req) = @_;
99
100 unless ($req->IsFastCGI()) {
77528196 101 return -1 if $run_once;
0833402a 102
77528196 103 $run_once = 1;
104 return 0;
0833402a 105 }
106 $req->Finish();
107 $req->{socket} = gensym();
7fa2de73 108 if ($req->{last} || !accept($req->{socket}, $req->{listen_sock})) {
77528196 109 $req->{error} = "accept";
110 return -1;
0833402a 111 }
112 my ($type, $id, $body) = $req->read_record();
113 if ($type != BEGIN_REQUEST) {
77528196 114 $req->{error} = "begin request";
115 return -1;
0833402a 116 }
117 my ($role, $flags) = unpack("nC", $body);
118 $req->{role} = $role;
119 $req->{flags} = $flags;
120 $req->{id} = $id;
121
122 %{$req->{env}} = ();
123 $req->{env}{FCGI_ROLE} = $FCGI::rolenames{$req->{role}};
124 my $param = FCGI::Stream->new($req, PARAMS);
125 my ($nlen, $vlen);
562f0c66 126 while (defined($nlen = read_nv_len($param)) &&
77528196 127 defined($vlen = read_nv_len($param)))
128 {
129 my ($name, $val);
130 read $param, $name, $nlen;
131 read $param, $val, $vlen;
132 $req->{env}{$name} = $val;
0833402a 133 }
134 $req->Bind;
135 $req->{accepted} = 1;
136
1b64d24d 137 return 0;
138}
0833402a 139
140sub UndoBindings {
141 my ($req) = @_;
142 untie ${$req->{in}};
143 untie ${$req->{out}};
144 untie ${$req->{err}};
145 $req->{bound} = 0;
146}
147
148sub Bind {
149 my ($req) = @_;
150 tie ${$req->{in}}, 'FCGI::Stream', $req, FCGI_STDIN;
151 tie ${$req->{out}}, 'FCGI::Stream', $req, FCGI_STDOUT;
152 tie ${$req->{err}}, 'FCGI::Stream', $req, FCGI_STDERR;
153 $req->{bound} = 1;
154}
155
156sub Attach {
157 my ($req) = @_;
158 $req->Bind() if ($req->{accepted} && !$req->{bound});
159}
160
161sub Detach {
162 my ($req) = @_;
163 $req->UndoBindings() if ($req->{accepted} && $req->{bound});
164}
165
166sub Finish {
167 my ($req) = @_;
168 return unless $req->{accepted};
169 if ($req->{bound}) {
77528196 170 $req->UndoBindings();
171 # apparently these are harmful
172 # close ${$req->{out}};
173 # close ${$req->{err}};
1b64d24d 174 }
0833402a 175 $req->{accepted} = 0;
176}
177
7fa2de73 178sub LastCall {
179 shift->{last} = 1;
180}
181
0833402a 182sub DESTROY {
183 shift->Finish();
184}
185
186sub read_record {
187 my ($self) = @_;
188 my ($header, $body);
189
190 read($self->{socket}, $header, 8);
191 my ($version, $type, $id, $clen, $plen) = unpack("CCnnC", $header);
192 read($self->{socket}, $body, $clen+$plen);
193 $body = undef if $clen == 0;
194 ($type, $id, $body);
195}
196
197sub read {
198 my ($self, $rtype, $len) = @_;
199 while (length $self->{buf} < $len) {
77528196 200 my ($type, $id, $buf) = $self->read_record();
201 return undef unless defined $buf;
202 if ($type != $rtype) {
203 $self->{error} = "unexpected stream type";
204 return 0;
205 }
206 $self->{buf} .= $buf;
b716743a 207 }
562f0c66 208 my ($newbuf, $result) = (substr($self->{buf}, $len),
8d7b81b0 209 substr($self->{buf}, 0, $len));
0833402a 210 $self->{buf} = $newbuf;
211 $result;
212}
213
214sub Flush {
215 my ($req) = @_;
216}
217
218sub write {
219 my ($self, $type, $content, $len) = @_;
220 return unless $len > 0;
221 $self->write_record($type, $content, $len);
34bfd355 222}
223
0833402a 224sub write_record {
4f396a01 225 my ($self, $type, $content, $length) = @_;
226 my $offset = 0;
227 while ($length > 0) {
77528196 228 my $len = $length > 32*1024 ? 32*1024 : $length;
229 my $padlen = (8 - ($len % 8)) % 8;
230 my $templ = "CCnnCxa${len}x$padlen";
231 my $data = pack($templ,
8d7b81b0 232 VERSION_1, $type, $self->{id}, $len, $padlen,
233 substr($content, $offset, $len));
77528196 234 syswrite $self->{socket}, $data;
235 $length -= $len;
236 $offset += $len;
4f396a01 237 }
0833402a 238}
239
240{ package FCGI::Stream;
241
242sub new {
243 my ($class, $src, $type) = @_;
244 my $handle = do { \local *FH };
245 tie($$handle, $class, $src, $type);
246 $handle;
247}
248
249sub TIEHANDLE {
250 my ($class, $src, $type) = @_;
251 bless { src => $src, type => $type }, $class;
252}
5baeeca7 253
0833402a 254sub READ {
255 my ($stream, undef, $len, $offset) = @_;
256 my ($ref) = \$_[1];
257 my $buf = $stream->{src}->read($stream->{type}, $len);
258 return undef unless defined $buf;
259 substr($$ref, $offset, 0, $buf);
260 length $buf;
261}
262
263sub PRINT {
264 my ($stream) = shift;
265 for (@_) {
02e74f89 266 $stream->{src}->write($stream->{type}, $_, length($_));
1d209997 267 }
02e74f89 268 return 1;
0833402a 269}
1d209997 270
0833402a 271sub CLOSE {
272 my ($stream) = @_;
273 $stream->{src}->write_record($stream->{type}, undef, 0);
1d209997 274}
5baeeca7 275
0833402a 276}
277
278EOP
279print OUT while <DATA>;
280close OUT;
281__END__
282
283# Preloaded methods go here.
794c66be 284
0833402a 285# Autoload methods go after __END__, and are processed by the autosplit program.
1d209997 286
0833402a 287*FAIL_ACCEPT_ON_INTR = sub() { 1 };
288
ef8432ef 289sub Request(;***$*$) {
f85665ba 290 my @defaults = (\*STDIN, \*STDOUT, \*STDERR, \%ENV, 0, FAIL_ACCEPT_ON_INTR());
e09efffb 291 $_[4] = fileno($_[4]) if defined($_[4]) && defined(fileno($_[4]));
0833402a 292 splice @defaults,0,@_,@_;
293 RequestX(@defaults);
294}
1d209997 295
0833402a 296package FCGI::Stream;
e40fb02c 297
0833402a 298sub PRINTF {
299 shift->PRINT(sprintf(shift, @_));
34bfd355 300}
301
420df423 302sub BINMODE {
303}
304
0833402a 305sub READLINE {
306 my $stream = shift;
307 my ($s, $c);
308 my $rs = $/ eq '' ? "\n\n" : $/;
309 my $l = substr $rs, -1;
310 my $len = length $rs;
311
312 $c = $stream->GETC();
313 if ($/ eq '') {
77528196 314 while ($c eq "\n") {
315 $c = $stream->GETC();
316 }
0833402a 317 }
318 while (defined $c) {
77528196 319 $s .= $c;
320 last if $c eq $l and substr($s, -$len) eq $rs;
321 $c = $stream->GETC();
0833402a 322 }
323 $s;
324}
1b64d24d 325
0833402a 326sub OPEN {
327 $_[0]->CLOSE;
328 if (@_ == 2) {
77528196 329 return open($_[0], $_[1]);
0833402a 330 } else {
77528196 331 my $rc;
332 eval("$rc = open($_[0], $_[1], $_[2])");
333 die $@ if $@;
334 return $rc;
0833402a 335 }
336}
1b64d24d 337
0bbb6895 338# Some things (e.g. IPC::Run) use fileno to determine if a filehandle is open,
339# so we return a defined, but meaningless value. (-1 being the error return
340# value from the syscall in c, meaning it can never be a valid fd no)
341# Probably a better alternative would be to return the fcgi stream fd.
342sub FILENO { -1 }
497802b1 343
0833402a 3441;
eede4b76 345
0833402a 346=pod
eede4b76 347
0833402a 348=head1 NAME
eede4b76 349
0833402a 350FCGI - Fast CGI module
eede4b76 351
0833402a 352=head1 SYNOPSIS
6b312a77 353
0833402a 354 use FCGI;
6b312a77 355
0833402a 356 my $count = 0;
357 my $request = FCGI::Request();
6b312a77 358
0833402a 359 while($request->Accept() >= 0) {
77528196 360 print("Content-type: text/html\r\n\r\n", ++$count);
0833402a 361 }
eede4b76 362
0833402a 363=head1 DESCRIPTION
eede4b76 364
0833402a 365Functions:
eede4b76 366
0833402a 367=over 4
eede4b76 368
0833402a 369=item FCGI::Request
eede4b76 370
0833402a 371Creates a request handle. It has the following optional parameters:
eede4b76 372
0833402a 373=over 8
eede4b76 374
0833402a 375=item input perl file handle (default: \*STDIN)
eede4b76 376
0833402a 377=item output perl file handle (default: \*STDOUT)
9915cd6d 378
0833402a 379=item error perl file handle (default: \*STDERR)
9915cd6d 380
0833402a 381These filehandles will be setup to act as input/output/error
88665260 382on successful Accept.
9915cd6d 383
0833402a 384=item environment hash reference (default: \%ENV)
9915cd6d 385
0833402a 386The hash will be populated with the environment.
9915cd6d 387
0833402a 388=item socket (default: 0)
9915cd6d 389
0833402a 390Socket to communicate with the server.
391Can be the result of the OpenSocket function.
392For the moment, it's the file descriptor of the socket
393that should be passed. This may change in the future.
9915cd6d 394
dcdf34f5 395You should only use your own socket if your program
396is not started by a process manager such as mod_fastcgi
562f0c66 397(except for the FastCgiExternalServer case) or cgi-fcgi.
dcdf34f5 398If you use the option, you have to let your FastCGI
399server know which port (and possibly server) your program
400is listening on.
401See remote.pl for an example.
402
0833402a 403=item flags (default: 0)
1d209997 404
0833402a 405Possible values:
1d209997 406
0833402a 407=over 12
9915cd6d 408
0833402a 409=item FCGI::FAIL_ACCEPT_ON_INTR
5baeeca7 410
0833402a 411If set, Accept will fail if interrupted.
412It not set, it will just keep on waiting.
5baeeca7 413
0833402a 414=back
5baeeca7 415
0833402a 416=back
5baeeca7 417
0833402a 418Example usage:
419 my $req = FCGI::Request;
5baeeca7 420
0833402a 421or:
422 my %env;
423 my $in = new IO::Handle;
424 my $out = new IO::Handle;
425 my $err = new IO::Handle;
426 my $req = FCGI::Request($in, $out, $err, \%env);
5baeeca7 427
0833402a 428=item FCGI::OpenSocket(path, backlog)
5baeeca7 429
0833402a 430Creates a socket suitable to use as an argument to Request.
5baeeca7 431
0833402a 432=over 8
eede4b76 433
0833402a 434=item path
eede4b76 435
0833402a 436Pathname of socket or colon followed by local tcp port.
420df423 437Note that some systems take file permissions into account
438on Unix domain sockets, so you'll have to make sure that
439the server can write to the created file, by changing
440the umask before the call and/or changing permissions and/or
441group of the file afterwards.
eede4b76 442
0833402a 443=item backlog
eede4b76 444
0833402a 445Maximum length of the queue of pending connections.
446If a connection
447request arrives with the queue full the client may receive
448an error with an indication of ECONNREFUSED.
eede4b76 449
0833402a 450=back
eede4b76 451
0833402a 452=item FCGI::CloseSocket(socket)
eede4b76 453
0833402a 454Close a socket opened with OpenSocket.
eede4b76 455
0833402a 456=item $req->Accept()
90a18d65 457
0833402a 458Accepts a connection on $req, attaching the filehandles and
459populating the environment hash.
460Returns 0 on success.
461If a connection has been accepted before, the old
462one will be finished first.
1b64d24d 463
0833402a 464Note that unlike with the old interface, no die and warn
465handlers are installed by default. This means that if
466you are not running an sfio enabled perl, any warn or
467die message will not end up in the server's log by default.
468It is advised you set up die and warn handlers yourself.
469FCGI.pm contains an example of die and warn handlers.
1b64d24d 470
0833402a 471=item $req->Finish()
1b64d24d 472
0833402a 473Finishes accepted connection.
474Also detaches filehandles.
475
476=item $req->Flush()
477
478Flushes accepted connection.
479
480=item $req->Detach()
481
482Temporarily detaches filehandles on an accepted connection.
1b64d24d 483
0833402a 484=item $req->Attach()
485
486Re-attaches filehandles on an accepted connection.
487
7fa2de73 488=item $req->LastCall()
489
490Tells the library not to accept any more requests on this handle.
491It should be safe to call this method from signal handlers.
492
493Note that this method is still experimental and everything
494about it, including its name, is subject to change.
495
0833402a 496=item $env = $req->GetEnvironment()
497
498Returns the environment parameter passed to FCGI::Request.
499
500=item ($in, $out, $err) = $req->GetHandles()
501
502Returns the file handle parameters passed to FCGI::Request.
503
504=item $isfcgi = $req->IsFastCGI()
505
506Returns whether or not the program was run as a FastCGI.
507
508=back
509
929a7b0c 510=HEAD1 LIMITATIONS
511
512FCGI.pm isn't Unicode aware, only characters within the range 0x00-0xFF are
513supported. Attempts to output strings containing characters above 0xFF results
514in a exception: (F) C<Wide character in %s>.
515
516Users who wants the previous (FCGI.pm <= 0.68) incorrect behavior can disable the
517exception by using the C<bytes> pragma.
518
519 {
520 use bytes;
521 print "\x{263A}";
522 }
523
524
0833402a 525=head1 AUTHOR
526
527Sven Verdoolaege <skimo@kotnet.org>
528
529=cut
530
531__END__