Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python CGIHTTPServer Default Directories

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?

like image 970
charleslparker Avatar asked Jul 12 '13 15:07

charleslparker


3 Answers

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.

like image 192
charleslparker Avatar answered Oct 24 '22 10:10

charleslparker


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
like image 31
Michael Scott Asato Cuthbert Avatar answered Oct 24 '22 10:10

Michael Scott Asato Cuthbert


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()
like image 42
masterxilo Avatar answered Oct 24 '22 10:10

masterxilo