This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Hello, CGI and HTML together!"
Hello, CGI with an error traceback!" print "
Trying to divide by 0 produces:",witherror( ) print "
The script does not reach this part..." except ZeroDivisionError: print "
<pre>" traceback.print_exc( ) sys.stderr = sys._ _stderr_ _ traceback.print_exc( )
Chapter 21: CGI Scripting and Alternatives
After imports, redirection, and content-type output, this example runs the script’s substantial part in the try clause of a try/except statement. In the except clause, the script outputs a
tag, terminating any current line, and then a <pre> tag to ensure that further line breaks are honored. Function print_exc of module traceback outputs all error information. Lastly, the script restores standard error and outputs error information again. Thus, the information is also in the error logs for later study, not just transiently displayed in the client browser: not very useful in this specific example, since the error is repeatable, but necessary to track down real-life errors.
The cgitb module
Reports an exception’s traceback to the browser. exception is a tuple with three items (type,value,tb), just like the result of calling sys.exc_info( ), covered in exc_info on page 168. When exception is None, the default, handle calls exc_info to get the information about the exception to display.
Installs an exception hook, via sys.excepthook, to diagnose propagated exceptions. The hook displays the exception traceback on the browser if display is true. The hook logs the exception traceback to a file in directory logdir if logdir is not None. In the traceback, the hook shows context lines of source code per frame. In practice, you can start all of your CGI scripts with: import cgitb cgitb.enable( )
and be assured of good error reporting to the browser with minimal effort on your part. When you don’t want users of your page to see Python tracebacks from your scripts on their browsers, you can call cgitb.enable(False,'/my/log/dir') and get the error reports, with tracebacks, as files in directory /my/log/dir instead.
Installing Python CGI Scripts Installation of CGI scripts depends on the web browser and host platform. A script coded in Python is no different in this respect from scripts coded in other languages. Of course, you must ensure that the Python interpreter and standard library are installed and accessible. On Unix-like platforms, you must set the x
CGI in Python |
The simplest way to provide good error reporting in CGI scripts, although not quite as flexible as the approach just outlined in the previous section, is to use module cgitb. Module cgitb supplies two functions.
permission bits for the script and use a so-called shebang line as the script’s first line—for example: #!/usr/local/bin/python
depending on the details of your platform and Python installation. If you copy or share files between Unix and Windows platforms, make sure the shebang line does not end with a carriage return (\r), which might confuse the shell or web server that parses the shebang line to find out which interpreter to use for your script.
Python CGI scripts on Microsoft web servers If your web server is Microsoft IIS or Microsoft PWS (Personal Web Server), assign file extensions to CGI scripts via entries in registry path HKLM\System\ CurrentControlSet\Services\W3Svc\Parameters\Script_Map. Each value in this path is named by a file extension, such as .pyg (value names start with a period). The value is the interpreter command (e.g., C:\Python24\Python.Exe -u %s %s). You may use file extensions such as .cgi or .py for this purpose, but I recommend a unique one such as .pyg instead. Assigning Python as the interpreter for all scripts named .cgi might interfere with your ability to use other interpreters for CGI purposes. Having all modules with a .py extension interpreted as CGI scripts is more accident-prone than dedicating a unique extension such as .pyg to this purpose and may interfere with your ability to have your Python-coded CGI scripts import modules from the same directories. With IIS 5 and later, you can use the Administrative Tools ➝ Computer Management applet to associate a file extension with an interpreter command line. This is performed via Services and Applications ➝ Internet Information Services. Rightclick either on [IISAdmin], for all sites, or on a specific web site, and choose Properties ➝ Configuration ➝ Add Mappings ➝ Add. Enter the extension, such as .pyg, in the Extension field, and the interpreter command line, such as C:\Python22\ Python.Exe -u %s %s, in the Executable field.
Python CGI scripts on Apache The popular free web server Apache is configured via directives in a text file (by default, httpd.conf). When the configuration has ScriptAlias entries, such as: ScriptAlias /cgi-bin/ /usr/local/apache/cgi-bin/
any executable script in the aliased directory can run as a CGI script. You may enable CGI execution in a specific directory by using for the Apache directive for that directory: Options +ExecCGI
In this case, to let scripts with a certain extension run as CGI scripts, you may also add a global AddHandler directive, such as: AddHandler cgi-script pyg
to enable scripts with extension .pyg to run as CGI scripts. Apache determines the interpreter to use for a script by the shebang line at the script’s start. Another way
Chapter 21: CGI Scripting and Alternatives
to enable CGI scripts in a directory (if global directive AllowOverride Options is set) is to use Options +ExecCGI in a file named .htaccess in that directory.
Python CGI scripts on Xitami The free, lightweight, simple web server Xitami (http://www.xitami.org) makes it easy to install CGI scripts. When any component of a URL is named cgi-bin, Xitami takes the URL as a request for CGI execution. Xitami determines the interpreter to use for a script by the shebang line at the script’s start, even on Windows platforms.
The Cookie Module The Cookie module supplies several classes, mostly for backward compatibility. CGI scripts normally use the following classes from module Cookie.
HTTP, per se, is a stateless protocol, meaning that it retains no session state between transactions. Cookies, as specified by the HTTP 1.1 standard, let web clients and servers cooperate to build a stateful session from a sequence of HTTP transactions.
A script does not directly instantiate class Morsel. However, instances of cookie classes hold instances of Morsel. An instance m of class Morsel represents a single cookie element: a key string, a value string, and optional attributes. m is a mapping. The only valid keys in m are cookie attribute names: 'comment', 'domain', 'expires', 'max-age', 'path', 'secure', and 'version'. Keys into m are case-insensitive. Values in m are strings, each holding the value of the corresponding cookie attribute.
A SimpleCookie instance c is a mapping. c’s keys are strings. c’s values are Morsel instances that wrap strings. c[k]=v implicitly expands to: c[k]=Morsel( ); c[k].set(k,str(v),str(v))
If input is not None, instantiating c implicitly calls c.load(input).
A SmartCookie instance c is a mapping. c’s keys are strings. c’s values are Morsel instances that wrap arbitrary values serialized with pickle. c[k]=v has the semantics: c[k]=Morsel( ); c[k].set(k,str(v),pickle.dumps(v))
(Module pickle is covered in “The pickle and cPickle Modules” on page 279.) Since you have no control over the code that executes during deserialization via pickle.loads, class SmartCookie offers no security whatsoever. Unless your script is exposed only on a trusted intranet, avoid SmartCookie; use SimpleCookie instead. You can use any cryptographic approach to build, and take apart again, the strings wrapped by Morsel instance values in SimpleCookie instances. Modules covered in “Encoding Binary Data as Text” on page 561 make it easy to encode arbitrary byte strings as text strings, quite apart from any cryptographic measures. SmartCookie is more convenient than SimpleCookie plus cryptography, encoding, and decoding. Convenience and security, however, are often in conflict. The choice is yours. Do not labor under the misapprehension that your system is secure because “after all, nobody knows what I’m doing”—to quote a famous principle of secure design, “Security through obscurity isn’t.” Good cryptography is a necessary (but not sufficient) condition for strong security. To use cryptography with Python, see the Python Cryptography Toolkit at http://www.amk.ca/python/code/crypto.
Chapter 21: CGI Scripting and Alternatives
Cookie methods An instance c of SimpleCookie or SmartCookie supplies the following methods.
When data is a string, load parses it and adds to c each parsed cookie. When data is a mapping, load adds to c a new Morsel instance for each item in data. Normally, data is string os.environ. get('HTTP_COOKIE','') to recover the cookies the client sent.
Returns a string s formatted as HTTP headers. You can print c. output( ) among your response’s HTTP headers to send to the client the cookies held in c. Each header’s name is string header, and headers are separated by string sep. If attrs is not None, s’s headers contain only cookie attributes whose names are in attrs.
Morsel attributes and methods An instance m of class Morsel supplies three read/write attributes: coded_value
The cookie’s value, encoded as a string; m’s output methods use m.coded_value key
The cookie’s name value
The cookie’s value, which is an arbitrary Python object Instance m also supplies the following methods.
Returns a string s formatted as an HTTP header that sets the cookie held in m. See also the output method of cookie instances.
Returns a string s that represents the cookie held in m, without decorations. attrs can be any container suitable as the righthand operand of in, such as a list, dict, or set; s contains only attributes whose names are in attrs.
Sets m’s attributes. key and coded_value must be strings.
Using module Cookie Module Cookie supports cookie handling in both client-side and server-side scripts. Typical usage is server-side, often in a CGI script (where you have no alternatives, to maintain session state, to the direct manipulation of cookies). The following example shows a simple CGI script using cookies: import Cookie, time, os, sys, traceback sys.stderr = sys.stdout try: # first, the script emits HTTP headers c = Cookie.SimpleCookie( ) c["lastvisit"]=str(time.time( )) print c.output( ) print "Content-Type: text/html" print # then, the script emits the response's body print "Hello, visitor!" # for the rest of the response, the scripts gets and decodes the cookie c = Cookie.SimpleCookie(os.environ.get("HTTP_COOKIE")) when = c.get("lastvisit") if when is None: print "
Welcome to this site on your first visit!" print "
Please click the 'Refresh' button to proceed" else: try: lastvisit = float(when.value) except: print "
Sorry, cannot decode cookie (%s)"%when.value print "<pre>" traceback.print_exc( )
Welcome back to this site!" print "
You last visited on %s"%formwhen print "" except: print "Content-Type: text/html" print print "<pre>" traceback.print_exc( )