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