Python CGIHTTPServer Default Directories

7.3k views Asked by At

I've got the following minimal code for a CGI-handling HTTP server, derived from several examples on the inner-tubes:

#!/usr/bin/env python

import BaseHTTPServer
import CGIHTTPServer
import cgitb;

cgitb.enable()  # Error reporting

server = BaseHTTPServer.HTTPServer
handler = CGIHTTPServer.CGIHTTPRequestHandler
server_address = ("", 8000)
handler.cgi_directories = [""]

httpd = server(server_address, handler)
httpd.serve_forever()

Yet, when I execute the script and try to run a test script in the same directory via CGI using http://localhost:8000/test.py, I see the text of the script rather than the results of the execution.

Permissions are all set correctly, and the test script itself is not the problem (as I can run it fine using python -m CGIHTTPServer, when the script resides in cgi-bin). I suspect the problem has something to do with the default CGI directories.

How can I get the script to execute?

3

There are 3 answers

0
charleslparker On BEST ANSWER

My suspicions were correct. The examples from which this code is derived showed the wrong way to set the default directory to be the same directory in which the server script resides. To set the default directory in this way, use:

handler.cgi_directories = ["/"]

Caution: This opens up potentially huge security holes if you're not behind any kind of a firewall. This is only an instructive example. Use only with extreme care.

0
Michael Scott Asato Cuthbert On

The solution doesn't seem to work (at least for me) if the .cgi_directories requires multiple layers of subdirectories ( ['/db/cgi-bin'] for instance). Subclassing the server and changing the is_cgi def seemed to work. Here's what I added/substituted in your script:

from CGIHTTPServer import _url_collapse_path
class MyCGIHTTPServer(CGIHTTPServer.CGIHTTPRequestHandler):  
  def is_cgi(self):
    collapsed_path = _url_collapse_path(self.path)
    for path in self.cgi_directories:
        if path in collapsed_path:
            dir_sep_index = collapsed_path.rfind(path) + len(path)
            head, tail = collapsed_path[:dir_sep_index], collapsed_path[dir_sep_index + 1:]
            self.cgi_info = head, tail
            return True
    return False

server = BaseHTTPServer.HTTPServer
handler = MyCGIHTTPServer
0
masterxilo On

Here is how you would make every .py file on the server a cgi file (you probably don't want that for production/a public server ;):

import BaseHTTPServer
import CGIHTTPServer
import cgitb; cgitb.enable()

server = BaseHTTPServer.HTTPServer

# Treat everything as a cgi file, i.e.
# `handler.cgi_directories = ["*"]` but that is not defined, so we need
class Handler(CGIHTTPServer.CGIHTTPRequestHandler):  
  def is_cgi(self):
    self.cgi_info = '', self.path[1:]
    return True

httpd = server(("", 9006), Handler)
httpd.serve_forever()