FastCGI in Jetty

Jetty can serve PHP, Python, or Ruby scripts via FastCGI. FastCGI is a network protocol primarily used by a web server to communicate to a FastCGI server. FastCGI servers are used to serve web content generated by dynamic web languages including PHP, Python, Ruby, Perl and others.

The servlet that processes CGI scripts is called org.eclipse.jetty.servlets.CGI. This servlet is asynchronous, therefore, we have to add the <async-supported>true</async-supported> to the web.xml file.

index.html
<!DOCTYPE html>
<html>
    <body>
        Get environment <a href="cgi-bin/evars.py">variables</a>
    </body>
</html>

When our web application starts, it shows this simple HTML file. A link refers to a Python CGI script to get environment variables.

evars.py
#!/usr/bin/python

import sys
import os
from cgi import escape

print "Content-type: text/html"
print
print "<!doctype html>"
print "<html>"
print "<body>"
print "<pre>"
for k in sorted(os.environ):
    print "<b>%s: </b>%s" %(escape(k), escape(os.environ[k]))
print "</pre>"
print "</body>"
print "</html>"

Our example will process this Python script. It creates a simple HTML page containing environment variables.

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
  
    <servlet>
        <servlet-name>CGI</servlet-name>
        <servlet-class>org.eclipse.jetty.servlets.CGI</servlet-class>
        <init-param>
            <param-name>Path</param-name>
            <param-value>/bin:/usr/bin:/usr/local/bin</param-value>
        </init-param>
        <init-param>
            <param-name>cgibinResourceBaseIsRelative</param-name>
            <param-value>true</param-value>
        </init-param>      
        <init-param> 
            <param-name>commandPrefix</param-name> 
            <param-value>/usr/bin/python</param-value> 
        </init-param>         
        <init-param>
            <param-name>cgibinResourceBase</param-name>
            <param-value>WEB-INF/cgi-bin</param-value>
        </init-param>
        <async-supported>true</async-supported>
        <load-on-startup>1</load-on-startup>
    </servlet>
        
    <servlet-mapping>
        <servlet-name>CGI</servlet-name>
        <url-pattern>/cgi-bin/*</url-pattern>
    </servlet-mapping>  
    
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>    
  
</web-app>

This is the application's web.xml file. It maps the CGI servlet to /cgi-bin/* URL pattern. In the welcome file list, we specify the index.html file containing a link to a Python script. The cgibinResourceBaseIsRelative sets the path to the cgi-bin directory to be relative to the web application document root directory. The commandPrefix parameter specifies the path to the Python interpreter.

build.xml
<?xml version="1.0" encoding="UTF-8"?>

<project name="FastCGIServlet" default="archive">
  
    <property name="name" value="cgiexample"/>
    <property environment="env"/>
    <property name="src.dir" value="src"/>
    <property name="web.dir" value="${src.dir}/web"/>
    <property name="dist.dir" location="dist"/>
    <property name="deploy.path" location="${env.JETTY_BASE}/webapps"/>
  
    <target name="init">
        <mkdir dir="${dist.dir}"/>
    </target>     
  
    <target name="archive" depends="init">
        <war destfile="${dist.dir}/${name}.war" 
             webxml="${web.dir}/WEB-INF/web.xml">
            <fileset dir="${web.dir}"/>
        </war>
        <echo>Archive created</echo>
    </target> 
  
    <target name="clean" depends="init">
        <delete dir="${dist.dir}"/>
        <echo>Cleaning completed</echo>
    </target>  
    
    <target name="deploy" depends="archive">
        <copy file="${dist.dir}/${name}.war" overwrite="true" 
              todir="${deploy.path}"/>
        <echo>Archive deployed</echo>
    </target>    
    
</project>

The Ant archive task creates a web archive containing the index.html file, web.xml file and a Python script in the WEB-INF/cgi-bin/ subdirectory. The deploy task copies the WAR file into the deployment directory of the Jetty base.

$ java -jar $JETTY_HOME/start.jar --add-to-start=http,deploy,servlets

Assuming that we have not yet enabled any module in the Jetty base, we enable these three modules. The Jetty CGI servlet is in the servlets module.

$ java -jar $JETTY_HOME/start.jar

We start the Jetty server. Now we can navigate to the http://localhost:8080/cgiexample/ URL.

Output of the Python script
Figure:Output of the Python script

In this chapter of the Jetty tutorial, we have executed a Python script using the Jetty's CGI servlet.