FastCGI Application on Windows Azure

FastCGI is a protocol for interfacing interactive programs with a web server like IIS. It is a variation of earlier Common Gateway Interface (CGI) and very useful to reduce the overhead associated with interfacing the IIS and CGI programs, allowing a server to handle more web page requests at once. Instead of creating a new process for every request, FastCGI can use a single persistent process which handles many requests over its lifetime. Processing of multiple requests simultaneously is achieved either by using a single connection with internal multiplexing (ie. multiple requests over a single connection) and/or by using multiple connections. Many such processes can exist, something that can increase stability and scalability, read more at Wikipedia and its original spec.

FastCGI is language and platform independent protocol (but mostly C/C++ in nature). Not too much development at protocol level of FastCGI as it is very stable protocol, but it can be use in many web application scenarios because it ca add two new benefits that can boost scalability and availability:

- Distributed computing: run FastCGI applications on a different machine
- Multiple and extensible roles: CGI applications compute the response to an HTTP request.

In this post, I will explain how to develop FastCGI on Windows Azure using C++. I took a simple FastCFI sample from Windows Azure SDK March 2009 CTP. The sample program is designed to run as a sub-process of a Windows Azure Web or Worker role. It is a simple web role that demonstrates running a FastCGI application. By reading this post, you will understand how to:

- Enabling native code execution within the service definition file
- Configuring FastCGI in the web.roleConfig file
- Calling the Microsoft Service Hosting Runtime Native Library from a native C++ code

Note:  You can use MS C/C++ compiler and MSBUild to compile.
           All the command scripts are ready in the sample. Or using VC++ build project. 

01  02

The FastCGIApplication in this sample is pretty simple. It logs information and read configuration settings by calling Microsoft Service Hosting Runtime Native Library (msshrt.lib and ServiceHosting.h). The Service Hosting Runtime Native Library provides a native API for interacting with the role management agent and with the local storage resource in the Windows Azure environment or in the development fabric. You have to make sure Microsoft Service Hosting Runtime Native Library installed in you machine, usually at :

C:\Program Files\Windows Azure SDK\v1.0\

Its definition was located in FastCGIApplication.proj. If you are using x64 machine like me, you have to change the msshrt.lib location to (ServiceHostingSDKInstallPath)\lib\x64.

<PropertyGroup>
   <ServiceHostingSDKInstallPath Condition="'$(ServiceHostingSDKInstallPath)'==''">
$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\ServiceHosting\v1.0@InstallPath)
</ServiceHostingSDKInstallPath> <ServiceHostingSDKInclude>%22$(ServiceHostingSDKInstallPath)\inc%22</ServiceHostingSDKInclude> <ServiceHostingSDKLib>%22$(ServiceHostingSDKInstallPath)\lib\x64\msshrt.lib%22</ServiceHostingSDKLib> <CPPCompiler>cl.exe /Zi</CPPCompiler> <OutputExe>FastCGIApplication.exe</OutputExe> </PropertyGroup>

03

Below is its main program:

#include "Common.h"
#include "FastCGI.h"
#include <stdio.h>
int __cdecl main(int argc, __in_ecount(argc) LPSTR argv[])
{
    Initialize();
    LogInformation("Starting FastCGI Processing");
    std::string msg = GetConfigurationSetting("MessageOfTheDay");
    FastCGI fastCGI(msg);
    fastCGI.ProcessRequests();
    LogInformation("Exited");
}

In the ProcessRequests(), this FastCGIApplication will calculte size of response based on information in message header, allocate memory for response,  and define response from FastCGI server.

void FastCGI::ProcessRequests()
{
    FCGI_Header headerOfMessage;
    FCGI_StdOutErrorRecord message_StdErr;

    DWORD dwBytesWritten = 0;
    DWORD dwError = 0;
    DWORD dwResponseSize  = 0;
    DWORD dwRequestId = 0;
    PBYTE pBuffer;
    HRESULT hr = S_OK;
    while ( TRUE )
    {                        
        ZeroMemory( &headerOfMessage, sizeof( headerOfMessage ) );
        Recieve((PBYTE)&headerOfMessage, sizeof(headerOfMessage) );
        
// Calculate size of response based on information in the message header dwResponseSize = ( headerOfMessage.contentLengthB1 << 8 ) + headerOfMessage.contentLengthB0 + headerOfMessage.paddingLength; if( dwResponseSize > 0 ) { // Allocate memory for response pBuffer = new BYTE[dwResponseSize + 1]; if ( NULL == pBuffer ) { dwError = ERROR_OUTOFMEMORY; Error("Could not allocate memory" ); } ZeroMemory( pBuffer, dwResponseSize ); Recieve(pBuffer, dwResponseSize ); } dwRequestId = (headerOfMessage.requestIdB1 << 8) + headerOfMessage.requestIdB0;
        // Switch based on header type and define your own response to each of the 
//
messages from the FastCGI Server switch( headerOfMessage.type ) { case FCGI_BEGIN_REQUEST : LogVerbose("FCGI_BEGIN_REQUEST"); break; case FCGI_PARAMS : LogVerbose("FCGI_PARAMS"); break; case FCGI_STDIN : LogVerbose("FCGI_STDIN"); ProcessRequest(dwRequestId); break; case FCGI_NULL_REQUEST_ID : LogVerbose("FCGI_NULL_REQUEST_ID" ); break; default : Error("Unhandled type obtained, quitting" ); break; } } //end while }

If you are using VC++, you can build the FastCGIApplication and debug your FastCGI_WebRole project. Make sure the the WebRole project has web.configrole where application full path is defined. Note that %RoleRoot% is point to the root of your WebRole project, the same location with web.configrole and web.config files:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.webServer>
    <fastCgi>
      <application fullPath="%RoleRoot%\FastCGIApplication.exe"/>
    </fastCgi>
  </system.webServer>
</configuration>


You also have to enable native code execution in Service definition file (ServiceDefinition.csdef), as shown in the following codes. 

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="FastCGI" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="WebRole" enableNativeCodeExecution="true">
    <InputEndpoints>
      <!-- Must use port 80 for http and port 443 for https when running in the cloud -->
      <InputEndpoint name="HttpIn" protocol="http" port="80" />
    </InputEndpoints>
    <ConfigurationSettings>
      <Setting name="MessageOfTheDay"/>
    </ConfigurationSettings>
  </WebRole>
</ServiceDefinition>


Ok, other thing that you should check is your web.config file. Make sure you have defaultDocument pointed to index.htm and has mapped the path of FastCGIApplication.exe.

<?xml version="1.0"?>
<configuration>
  <system.web>
   <compilation debug="true"/>
  </system.web>
  <system.webServer>
    <!-- Setup index.htm as a default document. -->
    <defaultDocument>
      <files>
        <add value="index.htm"/>
      </files>
    </defaultDocument>
    
    <!-- Map a particular path to our FastCGI application. -->
    <handlers>
      <add name="FastCGI Sample" 
           path="MessageOfTheDay" 
           verb="*" 
           modules="FastCgiModule" 
           scriptProcessor="%RoleRoot%\FastCGIApplication.exe" 
           resourceType="Unspecified" />
    </handlers>
  </system.webServer>
</configuration>


Now let see what is inside the index.htm. It basically a simple HTML page with a link to MessageOfTheDay. There is no page like that, because FastCGIApplication.exe is the interpreter who will response to the HTTP request.

<h1>A FastCGI Application</h1>
    The path <a href="MessageOfTheDay">MessageOfTheDay</a> is an example FastCGI application.
    The applications use the native runtime API to log information 
    and read configuration settings. After clicking on this page you can examine the logs 
    to see information about the handling of the request.

05
06

Ok, now let give more instances in Service configuration file (<Instances count="4"/>) then debug the WebRole project to see the local development fabric.

07

Want to see this application running in cloud? Simple, right click on the FastCGI web role project, then click publish. Visual Studio will create a ready to deploy package for you (fastcgi.cspkg and serviceconfiguration.cscfg) then redirect your browser to Windows Azure cloud provisioning site. You will need .NET passport and Azure invitation code to get access to that site. I create my FastCGI project there and deploy the FastCGI application in 4 steps:


1. Create a new project
08

2. Set the hosted service name (URL)

09

3. Prepare a staging deployment

10

4. Upload the project package and service configuration

11

Make sure that everything is well deployed. Azure use an effective way of HTTP deployment. 
 12

For more information about deploying your package and developing on Windows Azure, I would like to recommend you the "How Do I?" Videos for the Azure Services Platform. Enjoy!

Hope this helps!

Cheer – RAM

Published 03-29-2009 10:33 AM by risman