Mojo-Server-FastCGI-0.50000755001750001750 013120303057 14067 5ustar00arpiarpi000000000000README100644001750001750 304313120303057 15030 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50DESCRIPTION The release version 1.98 of Mojolicious has dropped FastCGI support because the code and test quality of the FastCGI code was not conforming to the standards of the rest of Mojolicious codebase. This code will now be maintained as a separate distribution, using the same namespace as before, so installing it alongside Mojolicious should give You the same functionality as before. REASONING Other Mojolicious users and I believe that FastCGI support is still relevant today so the goal is to have this distribution synced with core Mojolicious and have the code and the tests improved so that eventually it will be merged back in core Mojolicious. AUTHORS The original author of this code is Sebastian Riedel and the full list of contributors is available in the Mojolicious distribution. Please don't bother the authors of Mojolicious with bug reports or feature requests; this should be directed to the maintainer of this code. MAINTAINER The maintainer of this distribution is Árpád Szász . You can file bug reports or feature requests on Github: https://github.com/arpadszasz/mojo-server-fastcgi/issues CONTRIBUTE The code for this distribution is maintained on Github and any code contribution is welcome: https://github.com/arpadszasz/mojo-server-fastcgi Code has been contributed by the following: pboyd (Paul Boyd) sri (Sebastian Riedel) oetiker (Tobias Oetiker) stigtsp (Stig Palmquist) dmw397 (David Webb) BUGS - Autodetection of the FastCGI environment doesn't work. - Weak test suite. LICENSE100644001750001750 2127613120303057 15205 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50 The Artistic License 2.0 Copyright (c) 2000-2006, The Perl Foundation. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. Definitions "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. "You" and "your" means any person who would like to copy, distribute, or modify the Package. "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. "Source" form means the source code, documentation source, and configuration files for the Package. "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. Permission for Use and Modification Without Distribution (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. Permissions for Redistribution of the Standard Version (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. Distribution of Modified Versions of the Package as Source (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under (i) the Original License or (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. Aggregating or Linking the Package (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. Items That are Not Considered Part of a Modified Version (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. General Provisions (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Changes100644001750001750 125313120303057 15444 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50This file documents the revision history for Mojo-Server-FastCGI. 0.50 June 14, 2017 Update for Mojolicious 6.43 changes (dmw397) 0.41 January 31, 2013 - Fixed a bug where a body containing a single "0" will get mangled, and updated tests a bit (stigtsp) 0.4 October 25, 2012 - Fixed compatibility with mojolicious +3.21 (sri, oetiker) 0.3 July 13, 2012 - Compatibility with Mojolicious 3.x (oetiker) 0.2 November 02, 2011 - Compatibility with Mojolicious 2.x (sri) - Change log level for empty connection messages (pboyd) 0.1 September 27, 2011 - First release as a separate distribution dist.ini100644001750001750 113313120303057 15612 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50name = Mojo-Server-FastCGI author = Árpád Szász license = Artistic_2_0 copyright_holder = Árpád Szász copyright_year = 2017 version = 0.50 [Prereqs] Mojolicious = 6.43 [Prereqs / TestRequires ] Test::More = 0 File::Slurp = 0 [MetaResources] bugtracker.web = https://github.com/arpadszasz/mojo-server-fastcgi/issues repository.web = https://github.com/arpadszasz/mojo-server-fastcgi repository.url = git://github.com/arpadszasz/mojo-server-fastcgi.git repository.type = git [@Filter] bundle = @Basic remove = Readme remove = License META.yml100644001750001750 123413120303057 15421 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50--- abstract: 'FastCGI Server' author: - 'Árpád Szász ' build_requires: File::Slurp: '0' Test::More: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.009, CPAN::Meta::Converter version 2.150010' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Mojo-Server-FastCGI requires: Mojolicious: '6.43' resources: bugtracker: https://github.com/arpadszasz/mojo-server-fastcgi/issues repository: git://github.com/arpadszasz/mojo-server-fastcgi.git version: '0.50' x_serialization_backend: 'YAML::Tiny version 1.70' MANIFEST100644001750001750 42213120303057 15257 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.009. Changes LICENSE MANIFEST META.yml Makefile.PL README cgi-bin/mojolite-fastcgi.pl dist.ini lib/Mojo/Server/FastCGI.pm lib/Mojolicious/Command/fastcgi.pm t/mojo/apache_fastcgi.t t/mojo/fastcgi.t Makefile.PL100644001750001750 206213120303057 16122 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.009. use strict; use warnings; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "FastCGI Server", "AUTHOR" => "\x{c1}rp\x{e1}d Sz\x{e1}sz ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "Mojo-Server-FastCGI", "LICENSE" => "artistic_2", "NAME" => "Mojo::Server::FastCGI", "PREREQ_PM" => { "Mojolicious" => "6.43" }, "TEST_REQUIRES" => { "File::Slurp" => 0, "Test::More" => 0 }, "VERSION" => "0.50", "test" => { "TESTS" => "t/mojo/*.t" } ); my %FallbackPrereqs = ( "File::Slurp" => 0, "Mojolicious" => "6.43", "Test::More" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); mojo000755001750001750 013120303057 15217 5ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50/tfastcgi.t100644001750001750 26513120303057 17147 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50/t/mojo#!/usr/bin/env perl use Mojo::Base -strict; use Test::More tests => 1; # "I've gone back in time to when dinosaurs weren't just confined to zoos." use_ok 'Mojo::Server::FastCGI'; apache_fastcgi.t100644001750001750 777513120303057 20505 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50/t/mojo#!/usr/bin/env perl use Mojo::Base -strict; # Disable Bonjour, IPv6 and libev BEGIN { $ENV{MOJO_NO_BONJOUR} = $ENV{MOJO_NO_IPV6} = 1; $ENV{MOJO_IOWATCHER} = 'Mojo::IOWatcher'; } # mod_fastcgi doesn't like small chunks BEGIN { $ENV{MOJO_CHUNK_SIZE} = 131072 } use Test::More; use File::Spec; use File::Temp; use IO::Socket::INET; use Mojo::IOLoop; use Mojo::Template; use Mojo::UserAgent; use File::Slurp; # Mac OS X only test plan skip_all => 'Mac OS X required for this test!' unless $^O eq 'darwin'; plan skip_all => 'set TEST_APACHE to enable this test (developer only!)' unless $ENV{TEST_APACHE}; plan tests => 13; # "Robots don't have any emotions, and sometimes that makes me very sad." use_ok 'Mojo::Server::FastCGI'; # Setup my $port = Mojo::IOLoop->generate_port; my $dir = File::Temp::tempdir(CLEANUP => 1); my $config = File::Spec->catfile($dir, 'fcgi.config'); my $mt = Mojo::Template->new; # FastCGI setup my $fcgi = File::Spec->catfile($dir, 'test.fcgi'); write_file($fcgi, $mt->render(<<'EOF')); % use Config; #!<%= $Config{perlpath} %> use strict; use warnings; % use FindBin; use lib '<%= "$FindBin::Bin/../../lib" %>'; use Mojolicious::Lite; use Mojo::Server::FastCGI; use Mojolicious::Command::fastcgi; get '/' => { text =>'Your Mojo is working!' }; post '/upload' => sub { my $self = shift; $self->render_data($self->req->upload('file')->slurp); }; post '/chunked' => sub { my $self = shift; my $params = $self->req->params->to_hash; my @chunks; for my $key (sort keys %$params) { push @chunks, $params->{$key} } my $cb; $cb = sub { my $self = shift; $cb = undef unless my $chunk = shift @chunks || ''; $self->write_chunk($chunk, $cb); }; $self->$cb(); }; get '/bug-0-in-body' => sub { my $self = shift; $self->render(text=>"0"); }; Mojo::Server::FastCGI->new->run; 1; EOF chmod 0777, $fcgi; ok -x $fcgi, 'script is executable'; # Apache setup write_file($config, $mt->render(<<'EOF', $dir, $port, $fcgi)); % my ($dir, $port, $fcgi) = @_; % use File::Spec; ServerName 127.0.0.1 Listen <%= $port %> DocumentRoot <%= $dir %> LoadModule log_config_module libexec/apache2/mod_log_config.so ErrorLog <%= File::Spec->catfile($dir, 'error.log') %> LoadModule alias_module libexec/apache2/mod_alias.so LoadModule fastcgi_module libexec/apache2/mod_fastcgi.so PidFile <%= File::Spec->catfile($dir, 'httpd.pid') %> LockFile <%= File::Spec->catfile($dir, 'accept.lock') %> FastCgiIpcDir <%= $dir %> FastCgiServer <%= $fcgi %> -processes 1 Alias / <%= $fcgi %>/ EOF # Start my $pid = open my $server, '-|', '/usr/sbin/httpd', '-X', '-f', $config; sleep 1 while !IO::Socket::INET->new( Proto => 'tcp', PeerAddr => 'localhost', PeerPort => $port ); # Request my $ua = Mojo::UserAgent->new; my $tx = $ua->get("http://127.0.0.1:$port/"); is $tx->res->code, 200, 'right status'; is $tx->res->headers->content_length, 21, 'right "Content-Length" value'; is $tx->res->body, 'Your Mojo is working!', 'right content'; # HEAD request $tx = $ua->head("http://127.0.0.1:$port/"); is $tx->res->code, 200, 'right status'; is $tx->res->headers->content_length, 21, 'right "Content-Length" value'; is $tx->res->body, '', 'no content'; # Form with chunked response my $params = {}; for my $i (1 .. 10) { $params->{"test$i"} = $i } my $result = ''; for my $key (sort keys %$params) { $result .= $params->{$key} } my ($code, $body); $tx = $ua->post_form("http://127.0.0.1:$port/chunked" => $params); is $tx->res->code, 200, 'right status'; is $tx->res->body, $result, 'right content'; # Upload ($code, $body) = undef; $tx = $ua->post_form( "http://127.0.0.1:$port/upload" => {file => {content => $result}}); is $tx->res->code, 200, 'right status'; is $tx->res->body, $result, 'right content'; # Bug test, returning "0" as body breaks the response. $tx = $ua->get("http://127.0.0.1:$port/bug-0-in-body"); is $tx->res->body, "0", '0 returned in body'; # Stop kill 'INT', $pid; sleep 1 while IO::Socket::INET->new( Proto => 'tcp', PeerAddr => 'localhost', PeerPort => $port ); Server000755001750001750 013120303057 16730 5ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50/lib/MojoFastCGI.pm100644001750001750 2365213120303057 20676 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50/lib/Mojo/Serverpackage Mojo::Server::FastCGI; use Mojo::Base 'Mojo::Server'; use Errno qw/EAGAIN EINTR EWOULDBLOCK/; use IO::Socket; use constant DEBUG => $ENV{MOJO_FASTCGI_DEBUG} || 0; our $VERSION = '0.50'; # Roles my @ROLES = qw/RESPONDER AUTHORIZER FILTER/; my %ROLE_NUMBERS; { my $i = 1; for my $role (@ROLES) { $ROLE_NUMBERS{$role} = $i; $i++; } } # Types my @TYPES = qw/ BEGIN_REQUEST ABORT_REQUEST END_REQUEST PARAMS STDIN STDOUT STDERR DATA GET_VALUES GET_VALUES_RESULT UNKNOWN_TYPE /; my %TYPE_NUMBERS; { my $i = 1; for my $type (@TYPES) { $TYPE_NUMBERS{$type} = $i; $i++; } } # "Wow! Homer must have got one of those robot cars! # *Car crashes in background* # Yeah, one of those AMERICAN robot cars." sub accept_connection { my $self = shift; # Listen socket unless ($self->{listen}) { my $listen = IO::Socket->new; # Open unless ($listen->fdopen(0, 'r')) { $self->app->log->error("Can't open FastCGI socket fd0: $!"); return; } $self->{listen} = $listen; } $self->app->log->debug('FastCGI listen socket opened.') if DEBUG; # Accept my $c; unless ($c = $self->{listen}->accept) { $self->app->log->error("Can't accept FastCGI connection: $!"); return; } $self->app->log->debug('Accepted FastCGI connection.') if DEBUG; return $c; } sub read_record { my ($self, $c) = @_; return unless $c; # Header my $header = $self->_read_chunk($c, 8); return unless $header; my ($version, $type, $id, $clen, $plen) = unpack 'CCnnC', $header; # Body my $body = $self->_read_chunk($c, $clen + $plen); # No content, just paddign bytes $body = undef unless $clen; # Ignore padding bytes $body = $plen ? substr($body, 0, $clen, '') : $body; if (DEBUG) { my $t = $self->type_name($type); $self->app->log->debug( qq/Reading FastCGI record: $type - $id - "$body"./); } return $self->type_name($type), $id, $body; } sub read_request { my ($self, $c) = @_; $self->app->log->debug('Reading FastCGI request.') if DEBUG; # Transaction my $tx = $self->can('build_tx') ? $self->build_tx : $self->on_transaction->($self); $tx->connection($c); my $req = $tx->req; # Type my ($type, $id, $body) = $self->read_record($c); unless ($type && $type eq 'BEGIN_REQUEST') { $self->app->log->info("First FastCGI record wasn't a begin request."); return; } $ENV{FCGI_ID} = $tx->{fcgi_id} = $id; # Role/Flags my ($role, $flags) = unpack 'nC', $body; $ENV{FCGI_ROLE} = $tx->{fcgi_role} = $self->role_name($role); # Slurp my $buffer = ''; my $env = {}; while (($type, $id, $body) = $self->read_record($c)) { # Wrong id next unless $id == $tx->{fcgi_id}; # Params if ($type eq 'PARAMS') { # Normal param chunk if ($body) { $buffer .= $body; next; } # Params done while (length $buffer) { # Name and value length my $name_len = $self->_nv_length(\$buffer); my $value_len = $self->_nv_length(\$buffer); # Name and value my $name = substr $buffer, 0, $name_len, ''; my $value = substr $buffer, 0, $value_len, ''; # Environment $env->{$name} = $value; $self->app->log->debug(qq/FastCGI param: $name - "$value"./) if DEBUG; # Store connection information $tx->remote_address($value) if $name =~ /REMOTE_ADDR/i; $tx->local_port($value) if $name =~ /SERVER_PORT/i; } } # Stdin elsif ($type eq 'STDIN') { # Environment if (keys %$env) { $req->parse($env); $env = {}; } # EOF last unless $body; # Chunk $req->parse($body); # Error return $tx if $req->error; } } return $tx; } sub role_name { my ($self, $role) = @_; return unless $role; return $ROLES[$role - 1]; } sub role_number { my ($self, $role) = @_; return unless $role; return $ROLE_NUMBERS{uc $role}; } sub run { my $self = shift; # Preload application $self->app; # New incoming request while (my $c = $self->accept_connection) { # Request my $tx = $self->read_request($c); # Error unless ($tx) { $self->app->log->info("No transaction for FastCGI request."); next; } # Handle $self->app->log->debug('Handling FastCGI request.') if DEBUG; $self->can('emit') ? $self->emit(request => $tx) : $self->on_request->($self, $tx); # Response $self->write_response($tx); # Finish transaction $tx->closed; } } sub type_name { my ($self, $type) = @_; return unless $type; return $TYPES[$type - 1]; } sub type_number { my ($self, $type) = @_; return unless $type; return $TYPE_NUMBERS{uc $type}; } sub write_records { my ($self, $c, $type, $id, $body) = @_; return unless defined $c && defined $type && defined $id; $body //= ''; # Write records my $empty = $body ? 0 : 1; my $offset = 0; my $body_len = length $body; while (($body_len > 0) || $empty) { # Need to split content my $payload_len = $body_len > 32 * 1024 ? 32 * 1024 : $body_len; my $pad_len = (8 - ($payload_len % 8)) % 8; # FCGI version 1 record my $template = "CCnnCxa${payload_len}x$pad_len"; if (DEBUG) { my $chunk = substr($body, $offset, $payload_len); $self->app->log->debug( qq/Writing FastCGI record: $type - $id - "$chunk"./); } # Write whole record my $record = pack $template, 1, $self->type_number($type), $id, $payload_len, $pad_len, substr($body, $offset, $payload_len); my $woffset = 0; while ($woffset < length $record) { my $written = $c->syswrite($record, undef, $woffset); # Error unless (defined $written) { # Retry next if $! == EAGAIN || $! == EINTR || $! == EWOULDBLOCK; # Write error return; } $woffset += $written; } $body_len -= $payload_len; $offset += $payload_len; # Done last if $empty; } return 1; } sub write_response { my ($self, $tx) = @_; $self->app->log->debug('Writing FastCGI response.') if DEBUG; # Status my $res = $tx->res; my $code = $res->code || 404; my $message = $res->message || $res->default_message; $res->headers->status("$code $message") unless $res->headers->status; # Fix headers $res->fix_headers; # Headers my $c = $tx->connection; my $offset = 0; while (1) { my $chunk = $res->get_header_chunk($offset); # No headers yet, try again unless (defined $chunk) { sleep 1; next; } # End of headers last unless length $chunk; # Headers $offset += length $chunk; return unless $self->write_records($c, 'STDOUT', $tx->{fcgi_id}, $chunk); } # Body $offset = 0; while (1) { my $chunk = $res->get_body_chunk($offset); # No content yet, try again unless (defined $chunk) { sleep 1; next; } # End of content last unless length $chunk; # Content $offset += length $chunk; return unless $self->write_records($c, 'STDOUT', $tx->{fcgi_id}, $chunk); } # The end return unless $self->write_records($c, 'STDOUT', $tx->{fcgi_id}, undef); return unless $self->write_records($c, 'END_REQUEST', $tx->{fcgi_id}, pack('CCCCCCCC', 0)); } sub _nv_length { my ($self, $bodyref) = @_; # Try first byte my $len = unpack 'C', substr($$bodyref, 0, 1, ''); # 4 byte length if ($len & 0x80) { $len = pack 'C', $len & 0x7F; substr $len, 1, 0, substr($$bodyref, 0, 3, ''); $len = unpack 'N', $len; } return $len; } sub _read_chunk { my ($self, $c, $len) = @_; # Read my $chunk = ''; while (length $chunk < $len) { my $read = $c->sysread(my $buffer, $len - length $chunk, 0); unless (defined $read) { next if $! == EAGAIN || $! == EINTR || $! == EWOULDBLOCK; last; } last unless $read; $chunk .= $buffer; } return $chunk; } 1; __END__ =head1 NAME Mojo::Server::FastCGI - FastCGI Server =head1 SYNOPSIS use Mojo::Server::FastCGI; my $fcgi = Mojo::Server::FastCGI->new; $fcgi->on_request(sub { my ($self, $tx) = @_; # Request my $method = $tx->req->method; my $path = $tx->req->url->path; # Response $tx->res->code(200); $tx->res->headers->content_type('text/plain'); $tx->res->body("$method request for $path!"); # Resume transaction $tx->resume; }); $fcgi->run; =head1 DESCRIPTION L is a portable pure-Perl FastCGI implementation as described in the C. See L for deployment recipes. =head1 ATTRIBUTES L inherits all attributes from L. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 C my $c = $fcgi->accept_connection; Accept FastCGI connection. =head2 C my ($type, $id, $body) = $fcgi->read_record($c); Parse FastCGI record. =head2 C my $tx = $fcgi->read_request($c); Parse FastCGI request. =head2 C my $name = $fcgi->role_name(3); FastCGI role name. =head2 C my $number = $fcgi->role_number('FILTER'); FastCGI role number. =head2 C $fcgi->run; Start FastCGI. =head2 C my $name = $fcgi->type_name(5); FastCGI type name. =head2 C my $number = $fcgi->type_number('STDIN'); FastCGI type number. =head2 C $fcgi->write_record($c, 'STDOUT', $id, 'HTTP/1.1 200 OK'); Write FastCGI record. =head2 C $fcgi->write_response($tx); Write FastCGI response. =head1 DEBUGGING You can set the C environment variable to get some advanced diagnostics information sent to the L logger as C messages. MOJO_FASTCGI_DEBUG=1 =head1 SEE ALSO L, L, L. =cut cgi-bin000755001750001750 013120303057 15320 5ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50mojolite-fastcgi.pl100755001750001750 114013120303057 21254 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50/cgi-bin#!/usr/bin/env perl use 5.10.1; use strict; use utf8; use warnings; use Mojolicious::Lite; get '/' => sub { shift->render('index'); }; app->start('fastcgi'); __DATA__ @@ index.html.ep
Perl %== $^V
Mojolicious %== Mojolicious->VERSION
Mojo::Server::FastCGI %== Mojo::Server::FastCGI->VERSION
Command000755001750001750 013120303057 20430 5ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50/lib/Mojoliciousfastcgi.pm100644001750001750 257713120303057 22561 0ustar00arpiarpi000000000000Mojo-Server-FastCGI-0.50/lib/Mojolicious/Commandpackage Mojolicious::Command::fastcgi; use Mojo::Base 'Mojolicious::Command'; use Mojo::Server::FastCGI; our $VERSION = '0.50'; has description => <<'EOF'; Start application with FastCGI. EOF has usage => <<"EOF"; usage: $0 fastcgi EOF # "Interesting... Oh no wait, the other thing, tedious." sub run { Mojo::Server::FastCGI->new(app => shift->app)->run } 1; __END__ =head1 NAME Mojolicious::Command::fastcgi - FastCGI Command =head1 SYNOPSIS use Mojolicious::Command::fastcgi; my $fastcgi = Mojolicious::Command::fastcgi->new; $fastcgi->run; =head1 DESCRIPTION L is a command interface to L. =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 C my $description = $fastcgi->description; $fastcgi = $fastcgi->description('Foo!'); Short description of this command, used for the command list. =head2 C my $usage = $fastcgi->usage; $fastcgi = $fastcgi->usage('Foo!'); Usage information for this command, used for the help screen. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 C $fastcgi->run; Run this command. =head1 SEE ALSO L, L, L. =cut