Welcome, guest | Sign In | My Account | Store | Cart

Invoking 'runcgi.py target.cgi' starts a built-in web server listening on the localhost adapter, configures the server to run target.cgi as a CGI program, then launches the system's default web browser to get the URL of the target script. The CGI script need not be in Python. The terminal that launched runcgi.py will show the server's log, which reports requests, responses, and errors.

Python, 77 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/usr/bin/env python

#  runcgi.py by Bryan Olson
#  This Python program is free software. You may use it, distribute it,
#  and/or modify it under the same terms as Python itself.

"""
    Tests a cgi script, by launching a simple web server and sending the
    default browser to the target cgi program. Good for testing. Not secure.
"""

import BaseHTTPServer
import CGIHTTPServer
import thread
import os
import webbrowser
import sys
from optparse import OptionParser


def main():

    usage = "runcgi.py [options] target\n" + __doc__

    root_opt = "Set the server root directory. Defaults to the current directory."

    cgibin_opt = ("Set a cgi script directory, relative to the server root. "
        "Option may be given multiple times for multiple script directories. "
        "Defaults to the one directory holding target.")

    port_opt = "Set the server's port number. By default the system chooses it."

    query_opt = "URL query string, without the '?'. The default is no query"

    parser = OptionParser(usage=usage)
    parser.add_option("-r", "--root", default='.', help=root_opt)
    parser.add_option("-c", "--cgi-bin", action="append", dest="cgibin", help=cgibin_opt)
    parser.add_option("-p", "--port", type='int', default=0, help=port_opt)
    parser.add_option("-q", "--query", default='', help=query_opt)

    (options, args) = parser.parse_args()
    if len(args) != 1:
        print >> sys.stderr, "Error: need exactly one target cgi program."
        parser.print_help()
        sys.exit(-1)

    cgi_target = args[0]
    handler = CGIHTTPServer.CGIHTTPRequestHandler
    os.chdir(options.root)
    cgi_dirs = handler.cgi_directories
    if options.cgibin is not None:
        cgi_dirs[:] = options.cgibin
    else:
        cgi_dirs[:] = [os.path.split(cgi_target)[0]]
    for i in range(len(cgi_dirs)):
        if not cgi_dirs[i].startswith('/'):
            cgi_dirs[i] = '/' + cgi_dirs[i]
        if len(cgi_dirs[i]) > 1 and cgi_dirs[i].endswith('/'):
            cgi_dirs[i] = cgi_dirs[i][:-1]

    httpd = BaseHTTPServer.HTTPServer(('localhost', options.port), handler)
    thread.start_new_thread(httpd.serve_forever, ())

    url = 'http://%s:%d/%s' % ('localhost', httpd.server_port, cgi_target)
    if options.query:
        url = url + '?' + options.query
    try:
        webbrowser.open_new(url)
    except Exception, e:
        print >> sys.stderr, 'Failed automatic web browser launch: %s' % str(e)
        print >> sys.stderr, 'Target URL is:', url

    raw_input("Hit return to exit server.\n\n")
    sys.exit(0)

if __name__ == '__main__':
    main()

CGI debugging is notoriously frustrating. Using a CGI script requires interaction of several complex component; consequently a daunting variety of problems in coding or configuration result in failure. Worse, useful diagnostic output is typically buried in server log files.

Given a standard Python installation, runcgi.py offers a zero-configuration environment for first-cut testing of CGI scripts. It exploits the 'batteries included' facilities of Python to make the defaults just work in typical cases, and to assist programmers as much as possible in atypical cases.

The program follows Python conventions for command-line processing and documentation, so read the strings or invoke:

runcgi.py -h

for usage information. The important Python library classes that runcgi.py demonstrates are CGIHTTPServer, webbrowser, and optparse.

Limitations:

Runcgi.py uses the Python library's built-in web server, and has no notion of how to configure your production web server. It's value is in quickly diagnosing or ruling out a large class of bugs.