difference between cgi and FCGI::Request in perl - perl

I have a peice of code
my $fcgi_request = FCGI::Request(\*STDIN,\*STDOUT,\*STDERR, \%ENV,0,FCGI::FAIL_ACCEPT_ON_INTR);
while (1) {
my $cgi = new CGI('');
}
So what is the role of FCGI::Request and how it is different from CGI because new CGI() is also giving me request handle.

Disclaimer: This is mostly speculation.
It's likely that whoever implemented that code tried migrating an existing CGI application to FCGI to make it faster. If you look at the FCGI documentation you'll see that almost all the parameters that are passed to FCGI::Request are the default values anyway. The only not-default one is this (indentation mine, and actually in the code it's different).
flags (default: 0)
Possible values:
FCGI::FAIL_ACCEPT_ON_INTR
If set, Accept will fail if interrupted. It
not set, it will just keep on waiting.
Because those parameters are positional, the author of your code most likely thought it's a good idea to pass in all the defaults so not to change anything. That makes sense, but looks strange.
Then there is the loop in which the program accepts requests. Inside, there is the old CGI program. This program might use other features of CGI like HTML-generation (which is now discouraged), so the author probably left it in. Because of how CGI works (it reads environment variables) and the way FCGI works (also reads environment variables) that's not mutually exclusive.
Now if somewhere down in the program it says stuff like print $q->header('text/html') then that will go to STDOUT, which above was set as the filehandle that the FCGI request uses. So the FCGI handler will see the output, and all is well.
Now interesting is why there is a while (1) and not a while (my $fcgi_request->Accept() >= 0 ). It says that the Accept accepts a connection and attaches the handles. This should be in your code somewhere in the loop.

CGI is a protocol for passing an HTTP request to a process using a combination of environment variables and STDIN, and to receive a response using STDOUT. As such, the request can only be sent to a child created specifically to handle that request.
Launching a child for each request can be slow, especially if the program needs to be compiled before being executed. Fast CGI is a solution to this problem.
Fast CGI is is a protocol for passing an HTTP request to a process using a socket. As such, the request can be sent to a pre-existing process, and this process can handle multiple requests.
FCGI::Request accepts a Fast CGI request, and makes it look like a CGI request, allowing CGI.pm to be used. This allows familiar libraries to be used, and it allows CGI programs to be converted to Fast CGI programs with more ease.
In that particular snippet, FCGI::Request isn't actually used since $request->Accept() isn't being called. As written, it expects a CGI request, not a Fast CGI request.

Related

FastCGI or PSGI Interface to NGINX in 2021

This question I asked has resulted in me exploring directly interfacing my FastCGI script to NGINX, rather than using a reverse proxy to Apache. I successfully modified my FastCGI script to run as a daemon using some code I found online:
my $s = FCGI::OpenSocket(':9000',20);
my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%ENV, $s);
# Remaining code stays just as it does when using with Apache's mod_fcgid
while($request->Accept() >= 0) {
# Call core app subroutines.
}
It works, but near as I can tell this has a distinct disadvantage over mod_fcgid: I have one process running which will handle one request at a time and if that process dies, there's nothing to start it back up. There are references on Stack Overflow to code that properly spun off workers, but the sites referenced inevitably seem to have gone offline, much like FastCGI's own site.
So, I'm trying to figure out what I need to add and also -- pardon the pun -- figure out if I need to take a fork in this road. Here are the options that I am trying to consider, if I understand my issues correctly:
Directly implement some sort of forking mechanism, ideally it seems like it should (1) toss off the request to a process/thread/worker -- perhaps one that can stay alive for multiple requests -- and move on to being ready for the next request and (2) be independent enough from the workers that if something goes wrong with a worker, it doesn't bring down the whole system until I catch it and restart the main process (e.g. autorestart processes). If this can be done simply and reliably, this seems to have a huge appeal since the code already works with FastCGI.
Give up on direct FastCGI and convert to PSGI and use an application server to handle these things. Given that I'm using Perl, I'd guess Starman is the logical option, although I've been reading on uwsgi's PSGI support and it sounds almost ideal in "tyrant Emperor" mode, where it could run processes with different privileges, auto restart missing processes, etc.
Option 1 seems intriguing since it requires the least modification to my existing code and a FastCGI script started up without FastCGI still works like a normal CGI script. (I'm not running this code under FastCGI when it is used by sites that are very low traffic).
Option 2, though, feels like it might be more "modern." At least PSGI documentation seems to still be online, for example, and using Starman or uwsgi seem like they take care of the background stuff I need probably better than I would cooking up my own system. Downside: I'd need two startup scripts for my code: one to be used by the PSGI enabled sites and one for sites still running in CGI.
Update: Continuing to explore option 1, I read through this tutorial on Perl fork() which seems somewhat relevant. Would using fork to break off each FastCGI request be a good approach if I go with option 1? I assume I'd be at risk of fork bombing, although if I kept track of the number of forks and issued wait() if ($forks > 10); perhaps that would be a safe approach? (Or perhaps using Parallel::ForkManager to do that process watching.) Or would it be safer and/or more efficient using something like Thread::Queue and passing FastCGI request objects to a set a threads that are reliably already established? There seem to be plenty of pitfalls I might overlook, which then returns me to whether I should opt for Option 2.

Perl script running a periodic (main) task and providing a REST interface

I am working on a Perl script which does some periodic processing based on file-system contents.
The overall structure is like this:
# ... initialization...
while(1) {
# ... scan filesystem, perform actions depending on changes detected ...
sleep 5;
}
I would like to add the ability to input some data into this process by means of exposing an interface through HTTP. E.g. I would like to add an endpoint to skip the sleep, but also some means to input data that is processed in the next iteration. Additionally, I would like to be able to query some of the program's status through HTTP (i.e. a simple fork() to run the webserver-part in a separate process is insufficient?)
So far I have already used the Dancer2 framework once but it has a start; call that blocks and thus does not allow any other tasks (like my loop) to run. Additionally, I could of course move the code which is currently inside the loop to an endpoint exposed through Dancer2 but then I would need to call that periodically (though an external program?) which seems to be quite an obscure indirection compared to just having the webserver-part running in background.
Is it possible to unobtrusively (i.e. without blocking the program) add a REST-server capability to a Perl script? If yes: Which modules would be used for the purpose? If no: Should I really implement an external process to periodically invoke a certain endpoint or pursue a different solution altogether?
(I have tried to add a dancer2 tag, but could not do so due to insufficient reputation. Do not be mislead by this: I have so far only tried with Dancer2 not the Dancer (v.1))
You could try to launch your processing loop in a background thread, before you run start;.
See man perlthrtut
You probably want use threads::shared; to declare some variables shared between the REST part and the background thread. Or use dedicated queues/event mechanisms.

threads in Dancer

I'm using Dancer 1.31, in a standard configuration (plackup/Starman).
In a request I wished to call a perl function asynchronously, so that the request returns inmmediately. Think of the typical "long running operation" scenario, in which one wants to return a "processing page" with a refresh+redirect.
I (naively?) tried with a thread:
sub myfunc {
sleep 9; # just for testing a slow operation
}
any '/test1' => sub {
my $thr = threads->create('myfunc');
$thr->detach();
return "done" ;
};
I does not work, the server seems to freeze, and the error log does not show anything. I guess manual creation of threads are forbidden inside Dancer? It's an issue with PSGI? Which is the recommended way?
I would stay away from perl threads especially in a web server environment. It will most likely crash your server when you join or detach them.
I usually create a few threads (thread pool) BEFORE initializing other modules and keep them around for the entire life time of the application. Thread::Queue nicely provides communication between the workers and the main thread.
The best asynchronous solution I find in Perl is POE. In Linux I prefer using POE::Wheel::Run to run executables and subroutines asynchronously. It uses fork and has a beautiful interface allowing communication with the child process. (In Windows it's not usable due to thread dependency)
Setting up Dancer and POE inside the same application/script may cause problems and POE's event loop may be blocked. A single worker thread dedicated to POE may come handy, or I would write another server based on POE and just communicate with the Dancer application via sockets.
Threads are definitively iffy with Perl. It might be possible to write some threaded Dancer code, but to be honest I don't think we ever tried it. And considering that Dancer 1's core use simpleton classes, it might also be very tricky.
As Ogla says, there are other ways to implement asynchronous behavior in Dancer. You say that you are using Starman, which is a forking engine. But there is also Twiggy, which is AnyEvent-based. To see how to leverage it to write asynchronous code, have a gander at Dancer::Plugin::Async.

FastCGI with protocol = Tcp on IIS 7

I have tried to use IIS 7 (as included in Windows 7) to test a FastCGI library I am currently developing.
According to the original FastCGI spec, when an application is called, its stdin handle is replaced with a socket. By default, IIS uses a named pipe instead, but it is possible to configure it to use TCP, i.e. a socket.
When I try to use this socket in my test application, I get an WSAENOTSOCK error.
When I try to use a named pipe instead (after reconfiguring IIS), I run into similar problems. For example, I get a ERROR_INVALID_HANDLE when I try to use PeekNamedPipe. ReadFile and WriteFile however work correctly.
I guess the problem is that this handle is inherited from the parent process and the current process does not really know its exact type. It seems to assume that the handle represents a simple file.
Has anyone run into similar problems and knows a solution/workaround? Can I somehow update the in-process status of my handle such that the WIN32 API function will accept it as a socket/named pipe?
In case anyone else ever stumbles upon this: DuplicateHandle does the trick.
In fact, the function OS_LibInit of the libfcgi implementation shows how to start an FastCGI app that got its socket through stdin.

How can I get Perl's Jabber::SimpleSend to work with Gmail chat?

I'm trying to write a simple Perl script to send an Instant Message. Jabber seemed like it might be the most conducive protocol. But the following script fails:
#!/usr/bin/env perl
use Jabber::SimpleSend qw(send_jabber_message);
send_jabber_message('me#gmail.com',
'CENSORED',
'you#gmail.com',
'subject test',
"body test");
It says:
Can't call method "can_read" on an undefined value at
/opt/local/lib/perl5/site_perl/5.8.9/XML/Stream.pm line 1421.
As cartman's answer points out, the code should actually be
#!/usr/bin/env perl
use Jabber::SimpleSend qw(send_jabber_message);
send_jabber_message('me%40gmail.com#talk.google.com',
'CENSORED',
'you%40gmail.com#talk.google.com',
'subject test',
"body test");
But that fails with the following error:
No SASL mechanism found
at /usr/local/lib/perl5/site_perl/5.10.0/Authen/SASL.pm line 74
I do have the Authen::SASL cpan module installed.
Jabber::SimpleSend is the easier way to interact with a standard Jabber server but don't let the module name mislead you: gtalk is indeed a bit different, requiring TLS encryption (that Jabber::SimpleSend won't do) and a hostname change. You will get better results using Net::XMPP and dealing directly with its API.
See http://www.gridpp.ac.uk/wiki/Nagios_jabber_notification for a well-commented, fully working implementation in 75 lines of perl using Net::XMPP. It's inteded to send nagios notifications but it does exactly what you need.
I'm not familiar with the code, but that line in XML::Stream is where the module begins a select() loop. Line 523-524 is where is passes IO::Select a socket to the destination server, and IO::Select itself passes a blessed reference, which should never be undef the way XML::Stream uses it.
Something is probably modifying the "SELECT" element of the XML::Stream object in the Jabber modules, possibly in a misguided attempt to correct a server connection error. I'm sorry I couldn't be more specific.
In response to the update:
These are odd errors, and I've been meaning to look inside the Jabber modules anyway, so I took at look at the source. The following is based on looking at the latest versions of the modules used available from CPAN. This is probably not very useful unless you want to start subclassing these modules and adding code to see where something unexpected happens. (You can skip the next paragraph if you're not interested in the Jabber modules' internals.)
From the updated information, I've traced it to the point where Authen::SASL::Perl croaks on line 41. It needs a result from $parent->mechanism, and there are two possible causes, assuming Authen::SASL isn't broken. Either it's being called incorrectly with no arguments from Net::XMPP::Protocol (line 2968), which seems unlikely, or the "mechanisms" it set in the constructor for Authen::SASL don't exist. Net::XMPP::Protocol defines the "mechanisms" (GetStreamFeature called, line 2958; that method defined around line 3340) with return $self->{STREAM}->GetStreamFeature($self->GetStreamID(),$feature);, where $feature is just a string passed from the callee and the id part of the XML::Stream object's session.
Based on the original XML error and the possibility of the session id going bad, it appears that the server either sends bad data at some point unexpected to XML::Stream and unaccounted for by the modules using it. I'm not convinced that foo%40gmail.com#talk.google.com is the right user name format, but I don't know how that could be causing these errors without the Jabber server doing something wrong.
I would start fresh with different user names on a different server and see if Jabber::SimpleSend works at all, then try to capture the server's output somehow to see what XML::Stream is choking on.
Update: For what it's worth, I installed the module and I'm getting the exact same errors. Authen::SASL::Perl::PLAIN and all other prerequisites do exist. And when I set the user name to gmailaccountname#talk.google.com and enabled global warnings (eg, #!/usr/bin/perl -w or perl -w filename.pl), XML::Stream reveals a bunch of undefined value problems, and SimpleSend actually spits out the warning "Could not connect to Jabber server"! (No, I don't know what that really means :().
Update: I was trying to install Net::Jabber::Bot (I gave up after some ssl module errors) to see if it would solve anything, and I noticed its constructor has this option and note:
gtalk => 0 # Default to off, 1 for on. needed now due to gtalk differences from std jabber server.
which reinforces the idea that the server's doing something unusual, which XML::Stream doesn't bother to throw an exception for.
Your username should be me#gmail.com but the server name is talk.google.com. So the first parameter should be me#gmail.com#talk.google.com, but I am not sure if Perl can grok that double # signs. You may try to escape first # with %40 so that the first parameter is me%40gmail.com#talk.google.com .
Update I:
About the second error, looks like you are missing SASL authentication modules. GMail uses SASL Plain authentication. So do you have /usr/local/lib/perl5/site_perl/5.10.0/Authen/SASL/Perl/PLAIN.pm file ?
Looks like you require Authen::SASL::Cyrus (the C implementation) or Authen::SASL::Perl (the Perl implementation) to be installed as well as Authen::SASL (which simply tries to find the best option installed on your machine, and, for you, finds neither).
Check to see if you have one of them installed.
That's my reading of the source and the manual - I've not tested this, ymmv.