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.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
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
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| 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 |
Enter to Win an Adafruit Pi Cobbler Breakout 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 Pi Cobbler Breakout 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
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?




1 hour 33 min ago
1 hour 34 min ago
3 hours 34 min ago
12 hours 19 min ago
12 hours 53 min ago
13 hours 52 min ago
14 hours 42 min ago
18 hours 44 min ago
22 hours 31 min ago
22 hours 39 min ago