Faster Web Applications with SCGI
Listing 3. scgi_server.py returns request details.
SERVER_SOFTWARE: 'Apache' SCRIPT_NAME: '/scgitest' REQUEST_METHOD: 'GET' SERVER_PROTOCOL: 'HTTP/1.1' QUERY_STRING: '' CONTENT_LENGTH: '0' HTTP_ACCEPT_CHARSET: 'UTF-8,*' HTTP_USER_AGENT: 'Mozilla/5.0' SERVER_NAME: 'testserver.example.org' REMOTE_ADDR: '10.99.11.99' SERVER_PORT: '80' SERVER_ADDR: '192.0.34.166' DOCUMENT_ROOT: '/srv/www/' SERVER_ADMIN: 'webmaster@example.org' HTTP_HOST: 'testserver.example.org' REQUEST_URI: '/scgitest' HTTP_ACCEPT:'text/html,text/plain,*/*;q=0.5' REMOTE_PORT: '47088' HTTP_ACCEPT_LANGUAGE: 'en' SCGI: '1' HTTP_ACCEPT_ENCODING: 'gzip,deflate'
If that's not what you see, take a look at the shell where you ran the module. It may have printed some helpful error message there. Or, if there is no reaction from the SCGI server whatsoever, the request may not have reached it in the first place; check the Apache error log.
Once you have this running, congratulations—the worst is behind you. Stop your SCGI server process so it doesn't interfere with what we're going to do next.
Now, let's write a simple SCGI application in Python—one that prints the time.
We import the SCGI Python modules, then write our application as a handler for SCGI requests coming in through the Web server. The handler takes the form of a class that we derive from SCGIHandler. Call me unimaginative, but I've called the example handler class TimeHandler. We'll fill in the actual code in a moment, but begin with this skeleton:
#! /usr/bin/python
import scgi
import scgi.scgi_server
class TimeHandler(scgi.scgi_server.SCGIHandler):
pass # (no code here yet)
# Main program: create an SCGIServer object to
# listen on port 4000. We tell the SCGIServer the
# handler class that implements our application.
server = scgi.scgi_server.SCGIServer(
handler_class=TimeHandler,
port=4000
)
# Tell our SCGIServer to start servicing requests.
# This loops forever.
server.serve()
You may think it strange that we must pass the SCGIServer our handler class, rather than a handler object. The reason is that server object will create handler objects of our given class as needed.
This first incarnation of TimeHandler is still essentially the same as the original SCGIHandler, so all it does is print out request parameters. To see this in action, try running this program and opening the scgitest page in your browser as before. You should see something like Listing 3 again.
Now, we want to print the time in a form that a browser will understand. We can't simply start sending text or HTML; we first must emit an HTTP header that tells the browser what kind of output to expect. In this case, let's stick with simple text. Add the following near the top of your program, right above the TimeHandler class definition:
import time
def print_time(outfile):
# HTTP header describing the page we're about
# to produce. Must end with double MS-DOS-style
# "CR/LF" end-of-line sequence. In Python, that
# translates to "\r\n.
outfile.write("Content-Type: text/plain\r\n\r\n")
# Now write our page: the time, in plain text
outfile.write(time.ctime() + "\n")
By now, you're probably wondering how we will make our handler class call this function. With SCGI 1.12 or newer, it's easy. We can write a method TimeHandler.produce() to override SCGIHandler's default action:
class TimeHandler(scgi.scgi_server.SCGIHandler):
# (remove the "pass" statement--we've got real
# code here now)
# This is where we receive requests:
def produce(self, env, bodysize, input, output):
# Do our work: write page with the time to output
print_time(output)
We ignore them here, but produce() takes several arguments: env is a dict mapping CGI parameter names to their values. Next, bodysize is the size in bytes of the request body or payload. If you're interested in the request body, read up to bodysize bytes from the following argument, input. Finally, output is the file that we write our output page to.
If you have SCGI 1.11 or older, you need some wrapper code to make this work. In these older versions, you override a different method, SCGIHandler.handle_connection(), and do more of the work yourself. Simply copy the boilerplate code from Listing 4 into the TimeHandler class. It will set things up right and call produce(), so nothing else changes, and we can write produce() exactly as if we had a newer version of SCGI.
Listing 4. Boilerplate Code for SCGI 1.11 or Older
# Insert this definition into your handler class:
class TimeHandler(scgi.scgi_server.SCGIHandler):
# ...
def handle_connection(self, conn):
input = conn.makefile("r")
output = conn.makefile("w")
env = self.read_env(input)
bodysize = int(env.get('CONTENT_LENGTH',0))
try:
self.produce(env,bodysize,input,output)
finally:
output.close()
input.close()
conn.close()
Once again, run the application and check that it shows the time in your browser.
Next, to make things more interesting, let's pass some arguments to the request and have the program process them. The convention for arguments to Web applications is to tack a question mark onto the URL, followed by a series of arguments separated by ampersands. Each argument is of the form name=value. If we wanted to pass the program a parameter called pizza with the value hawaii, and another one called drink with the value beer, our URL would look something like http://example.org/scgitest?pizza=hawaii&drink=beer.
Any arguments that the visitor passes to the program end up in the single CGI parameter QUERY_STRING. In this case, the parameter would read “pizza=hawaii&drink=beer”. Here's something our TimeHandler might do with that:
class TimeHandler(scgi.scgi_server.SCGIHandler):
def produce(self, env, bodysize, input, output)
# Read arguments
argstring = env['QUERY_STRING']
# Break argument string into list of
# pairs like "name=value"
arglist = argstring.split('&')
# Set up dictionary mapping argument names
# to values
args = {}
for arg in arglist:
(key, value) = arg.split('=')
args[key] = value
# Print time, as before, but with a bit of
# extra advice
print_time(output)
output.write(
"Time for a pizza. I'll have the %s and a swig of %s!\n" %
(args['pizza'], args['drink'])
)
Now the application we wrote will not only print the time, but also suggest a pizza and drink as passed in the URL. Try it! You also can experiment with the other CGI parameters in Listing 3 to find more things your SCGI applications can do.
Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
| Trying to Tame the Tablet | May 08, 2013 |
- Using Salt Stack and Vagrant for Drupal Development
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- New Products
- Validate an E-Mail Address with PHP, the Right Way
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- The Pari Package On Linux
- Home, My Backup Data Center
- New Products
- Dart: a New Web Programming Experience
Enter to Win an Adafruit Prototyping Pi Plate Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Prototyping Pi Plate Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- Next winner announced on 5-21-13!
Free Webinar: Linux Backup and Recovery
Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.
In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.




4 hours 51 min ago
10 hours 29 min ago
16 hours 29 min ago
16 hours 51 min ago
17 hours 2 min ago
17 hours 6 min ago
17 hours 36 min ago
20 hours 27 min ago
21 hours 3 min ago
21 hours 4 min ago