1 #!/usr/bin/perl
2 #
3 # author Daniel Dominik Rudnicki
4 # thanks to: Piotr Romanczuk
5 # email
[email protected]
6 # version
0.4.
3
7 # webpage http:
//
www.nginx.eu/
8
#
9 # BASED @ http:
//
wiki.codemongers.com/NginxSimpleCGI
10
#
11 #
12 # use strict;
13 use FCGI;
14 use Getopt::Long;
15 use IO::All;
16 use Socket;
17
18 sub init {
19 GetOptions(
"
h
" => \$help,
20
"
verbose!
"=>\$verbose,
21
"
pid=s
" => \$filepid,
22
"
l=s
" => \$logfile,
23
"
S:s
" => \$unixsocket,
24
"
P:i
" => \$unixport) or usage();
25 usage()
if $help;
26
27 print
"
Starting Nginx-fcgi\n
"
if $verbose;
28 print
"
Running with $> UID
"
if $verbose;
29 print
"
Perl $]
"
if $verbose;
30
31 #
if ( $> ==
"
0
" ) {
32 # print
"
\n\tERROR\tRunning as a root!\n
";
33 # print
"
\tSuggested not to do so !!!\n\n
";
34 # exit
1;
35 # }
36
37
if ( ! $logfile ) {
38 print
"
\n\tERROR\t log file must declared\n
"
39 .
"
\tuse $0 with option -l filename\n\n
";
40 exit
1;
41 }
42 print
"
Using log file $logfile\n
"
if $verbose;
43
"
\n\n
" >> io($logfile);
44 addlog($logfile,
"
Starting Nginx-cfgi
");
45 addlog($logfile,
"
Running with $> UID
");
46 addlog($logfile,
"
Perl $]
");
47 addlog($logfile,
"
Testing socket options
");
48
49
if ( ($unixsocket && $unixport) || (!($unixsocket) && !($unixport)) ) {
50 print
"
\n\tERROR\tOnly one option can be used!\n
";
51 print
"
\tSuggested (beacuse of speed) is usage UNIX socket -S \n\n
";
52 exit
1;
53 }
54
55
if ($unixsocket) {
56 print
"
Daemon listening at UNIX socket $unixsocket\n
"
if $versbose;
57 addlog($logfile,
"
Deamon listening at UNIX socket $unixsocket
");
58 }
else {
59 print
"
Daemon listening at TCP/IP socket *:$unixport\n
"
if $verbose;
60 #
61 addlog($logfile,
"
Daemon listening at TCP/IP socket *:$unixport
");
62 }
63
64
if ( -e $filepid ) {
65 print
"
\n\tERROR\t PID file $filepid already exists\n\n
";
66 addlog($logfile,
"
Can not use PID file $filepid, already exists.
");
67 exit
1;
68 }
69
70
if ( $unixsocket ) {
71 print
"
Creating UNIX socket\n
"
if $verbose;
72 $socket = FCGI::OpenSocket( $unixsocket,
10 );
73
if ( !$socket) {
74 print
"
Couldn't create socket\n
";
75 addlog($logfile,
"
Couldn't create socket
");
76 exit
1;
77 }
78 print
"
Using UNIX socket $unixsocket\n
"
if $verbose;
79 }
else {
80 print
"
Creating TCP/IP socket\n
"
if $verbose;
81 $portnumber =
"
:
".$unixport;
82 $socket = FCGI::OpenSocket( $unixport,
10 );
83
if ( !$socket ) {
84 print
"
Couldn't create socket\n
";
85 addlog($logfile,
"
Couldn't create socket
");
86 exit
1;
87 }
88 print
"
Using port $unixport\n
"
if $verbose;
89 }
90 addlog($logfile,
"
Socket created
");
91
92
if ( ! $filepid ) {
93 print
"
\n\tERROR\t PID file must declared\n
"
94 .
"
\tuse $0 with option -pid filename\n\n
";
95 exit
1;
96 }
97 print
"
Using PID file $filepid\n
"
if $verbose;
98 addlog($logfile,
"
Using PID file $filepid
");
99
100 my $pidnumber = $$;
101 $pidnumber > io($filepid);
102 print
"
PID number $$\n
"
if $verbose;
103 addlog($logfile,
"
PID number $pidnumber
");
104
105 }
106
107 sub addzero {
108 my ($date) = shift;
109
if ($date <
10) {
110
return
"
0$date
";
111 }
112
return $date;
113 }
114
115 sub logformat {
116 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$iddst) = localtime(time);
117 my $datestring;
118 $year +=
1900;
119 $mon++;
120 $mon = addzero($mon);
121 $mday = addzero($mday);
122 $min = addzero($min);
123 $datestring =
"
$year-$mon-$mday $hour:$min
";
124
return($datestring);
125 }
126
127 sub addlog {
128 my ($log_file, $log_message) = @_;
129 my $curr_time = logformat();
130 my $write_message =
"
[$curr_time] $log_message
";
131 $write_message >> io($log_file);
132
"
\n
" >> io($log_file);
133 }
134
135 sub printerror {
136 my $message = @_;
137 print
"
\n Nginx FastCGI\tERROR\n
"
138 .
"
\t $message\n\n
";
139 exit
1;
140 }
141
142 sub usage {
143 print
"
\n Nginx FastCGI \n
"
144 .
"
\n\tusage: $0 [-h] -S string -P int\n
"
145 .
"
\n\t-h\t\t: this (help) message
"
146 .
"
\n\t-S path\t\t: path for UNIX socket
"
147 .
"
\n\t-P port\t\t: port number
"
148 .
"
\n\t-p file\t\t: path for pid file
"
149 .
"
\n\t-l file\t\t: path for logfile
"
150 .
"
\n\n\texample: $0 -S /var/run/nginx-perl_cgi.sock -l /var/log/nginx/nginx-cfgi.log -pid /var/run/nginx-fcgi.pid\n\n
";
151 exit
1;
152 }
153
154
155 init;
156 exit unless $@ =~ /^fakeexit/;
157 } ;
158
159 # fork part
160 my $pid = fork();
161
162
if( $pid ==
0 ) {
163 &main;
164 exit
0;
165 }
166
167 print
"
Forking worker process with PID $pid\n
"
if $verbose;
168 addlog($logfile,
"
Forking worker process with PID $pid
");
169 print
"
Update PID file $filepid\n
"
if $verbose;
170 addlog($logfile,
"
Update PID file $filepid
");
171 $pid > io($filepid);
172 print
"
Worker process running.\n
"
if $verbose;
173 addlog ($logfile,
"
Parent process $$ is exiting
");
174 exit
0;
175
176 sub main {
177 $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket );
178
if ($request) { request_loop()};
179 FCGI::CloseSocket( $socket );
180 }
181
182 sub request_loop {
183
while( $request->Accept() >=
0 ) {
184 # processing any STDIN input
from WebServer (
for CGI-POST actions)
185 $stdin_passthrough =
'';
186 $req_len =
0 + $req_params{
'
CONTENT_LENGTH
'};
187
if (($req_params{
'
REQUEST_METHOD
'} eq
'
POST
') && ($req_len !=
0) ){
188
while ($req_len) {
189 $stdin_passthrough .= getc(STDIN);
190 $req_len--;
191 }
192 }
193
194 # running the cgi app
195
if ( (-x $req_params{SCRIPT_FILENAME}) &&
196 (-s $req_params{SCRIPT_FILENAME}) &&
197 (-r $req_params{SCRIPT_FILENAME})
198 ){
199
foreach $key ( keys %req_params){
200 $ENV{$key} = $req_params{$key};
201 }
202
if ( $verbose ) {
203 addlog($logfile,
"
running $req_params{SCRIPT_FILENAME}
");
204 }
205 # http:
//
perldoc.perl.org/perlipc.html#Safe-Pipe-Opens
206
#
207 #open $cgi_app,
'
-|
', $req_params{SCRIPT_FILENAME}, $stdin_passthrough or print(
"
Content-type: text/plain\r\n\r\n
"); print
"
Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n
"; # addlog($logfile,
"
Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !
");
208 open $cgi_app,
'
-|
',
"
echo '$stdin_passthrough' | '$req_params{SCRIPT_FILENAME}'
" or print(
"
Content-type: text/plain\r\n\r\n
"); print
"
Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n
"; # addlog($logfile,
"
Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !
");
209
210
if ($cgi_app) {
211 print <$cgi_app>;
212 close $cgi_app;
213 }
214 }
else {
215 print(
"
Content-type: text/plain\r\n\r\n
");
216 print
"
Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n
";
217 addlog($logfile,
"
Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.
");
218 }
219 }
220 }