prev | Version 1107 (Mon Nov 27 20:46:08 2006) | next |
Figure 24.1: CGI Data Processing Cycle
Name | Purpose | Example |
---|---|---|
REQUEST_METHOD | What kind of HTTP request is being handled | GET or POST |
SCRIPT_NAME | The path to the script that's executing | /cgi-bin/post_photo.py |
QUERY_STRING | The query parameters following "?" in the URL | name=mydog.jpg&expires=never |
CONTENT_TYPE | The type of any extra data being sent with the request | img/jpeg |
CONTENT_LENGTH | How much extra data is being sent with the request (in bytes) | 17290 |
Table 24.1: Important CGI Environment Variables |
CONTENT_LENGTH
bytes to the CGI on standard input"Content-Type"
header to specify the MIME type of the data being sentFamily | Specific Type | Describes |
---|---|---|
Text | text/html | Web pages |
Image | image/jpeg | JPEG-format image |
Audio | audio/x-mp3 | MP3 audio file |
Video | video/quicktime | Apple Quicktime video format |
Application-specific data | application/pdf | Adobe PDF document |
Table 24.2: Example Mime Types |
Content-Type
header to tell the client to expect HTML…#!/usr/bin/env python # Headers and an extra blank line print 'Content-type: text/html' print # Body print '<html><body><p>Hello, CGI!</p></body></html>'
http://www.yourserver.com/cgi-bin/hello_cgi.py
cgi-bin
directoryFigure 24.2: Basic CGI Output
#!/usr/bin/env python import os, cgi # Headers and an extra blank line print 'Content-type: text/html' print # Body print '<html><body>' keys = os.environ.keys() keys.sort() for k in keys: print '<p>%s: %s</p>' % (cgi.escape(k), cgi.escape(os.environ[k])) print '</body></html>'
Figure 24.3: Environment Variable Output
<form>…</form>
elementaction
attribute specifies the URL to send data tomethod
attribute specifies the type of HTTP request to send"POST"
for HTML forms<select/>
elements to let users choose values from a list<option/>
elements<input/>
elements for other kind of datatype
is "text"
, get a one-line text entry boxtype
is "checkbox"
, get an on/off checkbox"submit"
and "reset"
create buttons to submit the form, or re-set the data to initial valuesFigure 24.4: A Simple Form
<input/>
element has a name
attributeos.environ['REQUEST_METHOD']
: "POST"
os.environ['SCRIPT_NAME']
: "/cgi-bin/simple_form.py"
os.environ['CONTENT_TYPE']
: "application/x-www-form-urlencoded"
os.environ['REQUEST_LENGTH']
: "80"
sequence=GATTACA&search_type=Similarity+match&program=FROG-11&program=Bayes-Hart
cgi
module insteadFieldStorage
FieldStorage
object is created, it reads and stores information contained in the URL and environmentsys.stdin
#!/usr/bin/env python import cgi print 'Content-type: text/html' print print '<html><body>' form = cgi.FieldStorage() for key in form.keys(): value = form.getvalue(key) if isinstance(value, list): value = '[' + ', '.join(value) + ']' print '<p>%s: %s</p>' % (cgi.escape(key), cgi.escape(value)) print '</body></html>'
URL | Value of a | Value of b |
---|---|---|
http://www.third-bit.com/swc/show_params.py?a=0 | "0" | None |
http://www.third-bit.com/swc/show_params.py?a=0&b=hello | "0" | "hello" |
http://www.third-bit.com/swc/show_params.py?a=0&b=hello&a=22 | [0, 22] | "hello" |
Table 24.3: Example Parameter Values |
import cgitb; cgitb.enable()
to the top of the programcgitb
is the CGI traceback moduleFieldStorage
value is a string or a list is tediousFieldStorage.getfirst(name)
to get the unique valueFieldStorage.getlist(name)
always returns a list of valuesname
Figure 24.5: Three Tier Architecture
Hi, is anyone reading this site? I was wondering the same thing. I wasn't sure if we were supposed to post here. Good point. Is there way to delete messages?
newmessage
is there, append it, and display resultsnewmessage
isn't there, someone's visiting the page, rather than submitting the form# Get existing messages. infile = open('messages.txt', 'r') lines = [x.rstrip() for x in infile.readlines()] infile.close() # Add more data? form = cgi.FieldStorage() if form.has_key('newmessage'): lines.append(form.getfirst('newmessage')) outfile = open('messages.txt', 'w') for line in lines: print >> outfile, line outfile.close()
# Display. print 'Content-Type: text/html' print print '<html><body>' for line in lines: print '<p>' + line + '</p>' print ''' <form action="http://www.third-bit.com/swc/message_form.py" method="post"> <p>Your message: <input name="newmessage" type="text"/> </p> <p> <input type="submit"/> <input type="reset"/> </p> </form> ''' print '</body></html>'
Kid
in Pythonmessage_form.py
opens messages.txt
, reads lines, closes filemessages.txt
, reads the same lines, closes filePython Cookbook
includes a generic file locking function that works on both Unix and Windows# Get existing messages. msgfile = open('messages.txt', 'r+') fcntl.flock(msgfile.fileno(), fcntl.LOCK_EX) lines = [x.rstrip() for x in msgfile.readlines()] # Add more data? form = cgi.FieldStorage() if form.has_key('newmessage'): lines.append(form.getfirst('newmessage')) msgfile.seek(0) for line in lines: print >> msgfile, line # Unlock and close. fcntl.flock(msgfile.fileno(), fcntl.LOCK_UN) msgfile.close()
Figure 24.6: Cookies
Cookie.SimpleCookie
SmartCookie
: it is potentially insecure"HTTP_COOKIE"
SimpleCookie
"HTTP_COOKIE"
value to the cookie's load
method# Get old count. count = 0 if os.environ.has_key('HTTP_COOKIE'): cookie = Cookie.SimpleCookie() cookie.load(os.environ['HTTP_COOKIE']) if cookie.has_key('count'): count = int(cookie['count'].value) # Create new count. count += 1 cookie = Cookie.SimpleCookie() cookie['count'] = count # Display. print 'Content-Type: text/html' print cookie print print '<html><body>' print '<p>Visits: %d</p>' % count print '</body></html>'
time.asctime(time.gmtime())
to create the valueExercise 24.1:
One way to test a CGI application is to send it HTTP requests, and examine the responses. Write a program that takes a hostname, port, and partial URL as command-line parameters, and sends the URL to the server identified by the hostname and port. The program should display the status code, reason, headers, and response page (if any) that are returned by the web server.
For example, if your program is run as httptest
localhost 80 /greeting.html
, it should send a request for
/greeting.html
to a web server running on port 80 on the
local machine, and display something like:
STATUS: 200 REASON: OK HEADERS: content-length [49] server ['Apache/2.0.54 (Debian GNU/Linux) DAV/2 SVN/1.1.4 mod_python/3.1.3 Python/2.3.5] last-modified ['Wed, 19 Apr 2006 13:59:19 GMT'] date ['Sun, 30 Apr 2006 14:12:13 GMT'] content-type ['text/html'] PAGE: <html> <body> <h1>Hello, CGI!</h1> </body> </html>
What are the pros and cons of testing a CGI application this way?
Exercise 24.2:
Another way to test a CGI application is to construct a mock
container to take the place of the web server. As described in
the lecture, CGI applications read data from environment
variables and standard input; by using the subprocess
module described in the integration
lecture, you can run the CGI yourself, passing it
whatever test data you want. Write a program that does this.
(For bonus marks, explain how you would test the mock
container…)
Exercise 24.3:
The third way to test a CGI application is to construct a
mock container that calls the CGI directly, rather than creating
a new process and passing it data through environment variables
and standard input. In order for this to work, the CGI program
must import specially-crafted versions of the sys
and
os
libraries that provide the CGI with data from the
testing program, rather than reading it from the real
sources:
if testing: import test_sys as sys import test_os as os else: import sys, os
What other changes must be made to the CGI application to allow it to be tested this way? What are the pros and cons of making such changes?
prev | Copyright © 2005-06 Python Software Foundation. | next |