[FASTCGI] help needed...

Tom Bowden charles_thomas at mac.com
Fri Mar 11 21:12:42 EST 2011


Speaking as a recent convert (of about a year or so) I would  
certainly hope that you don't lose hope with FastCgi.

At first blush -- it isn't stdout that you're supposed to write to...

Some tips/pointers that I have gleaned from this newsgroup and the  
examples in the code -- along with how I use fastcgi:

I have applications that must select on sockets from postgres,  
inotifyd, and fastcgi -- so I can't use fcgi_* .  So I use the thread- 
safe version of FCGX functions.
I also have to play around a lot with headers -- to pass cookies,  
custom status codes, etc.  So I create a number of ostringstream  
objects, write to them - and then dump them out as I need to with  
FCGX_PutStr().

What helped me the most -- with the paradigm of fastcgi -- is that  
I'm not really receiving from stdin and stdout (anonymous pipes  
associated with program).  Instead I am talking with sockets that are  
hidden by the API.
Here's some snippets.. FWIW.  If more complete examples are needed I  
can post them.,...  but perhaps this is enough.



In my startup of an object that communicates:
void IDOTicket::startup()
{
         FCGX_Init();
         FCGX_InitRequest(&_request, 0, 0);
         fcntl(FCGI_LISTENSOCK_FILENO, F_SETFL, O_NONBLOCK);
         _cin_streambuf = cin.rdbuf();
         _cout_streambuf = cout.rdbuf();
         _cerr_streambuf = cerr.rdbuf();

}

When I receive notification that there is a request to process:

int IDOTicket::process_fastcgi_environment(Json::Value& pc)
{
         int fcgx_method = FCGX_UNDEFINED;
         if (FCGX_Accept_r(&_request) != 0) {
             .. do stuff here ..
}




When I read from the socket:

long IDOTicket::read_xml_request(std::string& content_string)
{
         char * clenstr = FCGX_GetParam("CONTENT_LENGTH",  
_request.envp);
         unsigned long clen = STDIN_MAX;
         if (clenstr) {
           clen = strtol(clenstr, &clenstr, 10);
           if (*clenstr) {
             clen = STDIN_MAX;
           }

           // *always* put a cap on the amount of data that will be read
           if (clen > STDIN_MAX) {
             clen = STDIN_MAX;
           }

           content_string.resize( clen );
           std::string input_str;
           FCGX_GetStr((char*)content_string.data(), clen, _request.in);
           _ticket_interface_object->input(xmlParseMemory 
( content_string.c_str(), content_string.size()));

         } else {
           // *never* read stdin when CONTENT_LENGTH is missing or  
unparsable
           content_string.empty();
           clen = 0;
         }

         // Chew up any remaining stdin - this shouldn't be necessary
         // but is because mod_fastcgi doesn't handle it correctly.
         // ignore() doesn't set the eof bit in some versions of glibc++
         // so use gcount() instead of eof()...
         do {
           cin.ignore(1024);
         } while (cin.gcount() == 1024);

         if ( content_string.empty() ) {
           return 0L;
         } else {
           return content_string.size();
         }
}

WHEN I READ An environmental variable passed from apache, created by  
the fastcgi manager, and then consumed in my app:

         char* const* envp = _request.envp;

         for ( envp = _request.envp; *envp; ++envp) {
           Json::Value p_context = Json::Value(objectValue);
           std::string name;
           std::string value;
           if ( IDOPattern( PCRE_POST_REQUEST_METHOD)->PartialMatch 
( (*envp),&name, &value ) ) {
             fcgx_method = FCGX_POST;
           } else if ( IDOPattern( PCRE_GET_REQUEST_METHOD)- 
 >PartialMatch( (*envp),&name, &value ) ) {
             fcgx_method = FCGX_GET;
           } else if ( IDOPattern( PCRE_QUERY_STRING)->PartialMatch 
( (*envp), &name, &value) ) {
             std::string param_name;
             std::string param_value;
             std::string param_post;
             while ( IDOPattern( PCRE_SERIALIZED_FORM)->PartialMatch 
( value.c_str(), &param_name, &param_value, &param_post) ) {
               p_context[HAS_NAME_OF] = param_name;
               p_context[HAS_TYPE_OF] = param_name;
               p_context[HAS_VALUE_OF] = param_value;
               pc.append(p_context);
               value = param_post;
             }
           }
         }



WHEN I am writing to the socket:

           if ( data_stream.str().size() < 1 ) {
             http_stream << "Content-Length: " << content_stream.str 
().size() << std::endl;
           } else {
             content_stream << data_stream.str() << std::endl;
             http_stream << "Content-Length: " << content_stream.str 
().size() << std::endl;
           }
           header_stream << std::endl;

           if ( http_stream.str().size() > 0) {
             FCGX_PutStr(http_stream.str().c_str(), http_stream.str 
().size(), _request.out);
           }
           if ( header_stream.str().size() > 0) {
             FCGX_PutStr(header_stream.str().c_str(),  
header_stream.str().size(), _request.out);
           }
           if ( content_stream.str().size() > 0) {
             FCGX_PutStr(content_stream.str().c_str(),  
content_stream.str().size(), _request.out);
           }
         }


When I am finished with the socket/call of a single request:

         FCGX_Finish_r(&_request);



AS FOR LINKING:

Snippets from my Makefile

INCS += -I/usr/include/fastcgi

LIBS +=-lxslt
LIBS +=-lfcgi++
LIBS +=  $(PCRE_LIB_OPS) -lpcrecpp $(CURL_LIB_OPS) $ 
(READLINE_LIB_OPS)  \
         -L/usr/lib -lpthread -lm -ldl -lxml2 -lz


On Mar 11, 2011, at 7:35 AM, Majed Al-Dolaimi wrote:

> Hi guys,
> I am a bit disappointed in the FastCGI documentation, as many other  
> people are. However I am not losing hope with it.
>
> 1 - I installed the apache mod_fcgid  from SUSE website and it  
> seems to be working..
> 2 - I configured, compiled the fcgi-(*-*).tar.gz and added the libs  
> to the /usr/lib.
> 3 - Added the -Ifcgi++ (or -Ifcgi ) library to my Makefile... my  
> compiler is not complaining
> 4 - Added the FCGI_Accept() loop to my main routing in my c++ app...
>
> RESULTS: When I run the whole thing ...
> 5 - my app runs (it shows on the process monitor as a sleeping  
> process) and does not stop immediately which fine and dandy
> 6 - I only get a blank page in the browser. Even an error message  
> from my WWW server does not show up.
> I tried flushing the std::cout as well as writing to stdout file  
> descrptier then flush it... nothing shows up on the browser screen..
>
>  What I could not understand is making sure the linker searches for  
> the BSD socket library. Since the ldconfig did not complain, I  
> assumed it found it, right?
>
> Your help will pay back to fastcgi... so please help me out..
>
> Majed Dolaimi
> C++/ web developer
> _______________________________________________
> FastCGI-developers mailing list
> FastCGI-developers at mailman.fastcgi.com
> http://mailman.pins.net/mailman/listinfo.cgi/fastcgi-developers



More information about the FastCGI-developers mailing list