Python CGIHTTPServer Default Directories
Asked Answered
C

3

6

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?

Clump answered 12/7, 2013 at 15:5 Comment(2)
Thanks for the answer! This helped me sort out a Python-only server, which I'd been trying to do for ages. Worth pointing out that the canonical "correct" shebang is "#!/usr/bin/env python" - I've been caught out by that before!Midlothian
@Midlothian - Glad my struggle with this could provide you with some clarity. I've updated the shebang as you suggested. Thanks!Clump
C
6

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.

Clump answered 12/7, 2013 at 15:5 Comment(0)
L
3

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
Lockwood answered 18/8, 2014 at 0:1 Comment(0)
S
2

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()
Sherburn answered 2/5, 2016 at 18:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.