#!/usr/bin/python
# encoding: iso-8859-1
"""
	A simple CGI webserver with basic mod_rewrite support
	written in Python.

	Copyright (c) Phillip Berndt, 2006

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	To view the whole GPL, go to http://www.gnu.org/licenses/gpl.txt
"""
import BaseHTTPServer, SimpleHTTPServer, CGIHTTPServer, signal, sys, os, re, urllib, shutil

"""
	Settings
"""

"The htdocs directory."
htdocs = "./"

"File extensions associated with CGI executables"
extensions = {
	"php": "/usr/bin/php-cgi",
	"pl": "/usr/bin/perl"
}

"""
	End of settings
"""

class RequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
	"""
		This is a customized CGIHTTPRequestHandler, which
		is able to execute CGI Scripts based upon file
		extensions.

		You'll have to set the class attributes "rewriteRules"
		and "extensions" before using this class.
	"""
	rewriteRules = []
	extensions = {}
		
	def is_cgi(self):
		self.orginalPath = urllib.unquote(self.path)
		orginalURL = self.path
		url = self.path.split("?", 2)

		# Rewrite URL if a rule is matched
		for rewriteRule in self.rewriteRules:
			match = re.search(rewriteRule[0], url[0])
			if match == None: continue
			url[0] = re.sub("(%s)" % rewriteRule[0], re.sub(r"\$([0-9])", lambda val: r"\%d" % (int(val.group(1)) + 1), rewriteRule[1]), url[0])

			newUrl = url[0].split("?", 2)
			if len(newUrl) < 2 and len(url) == 2:
				newUrl.append(url[1])
			elif len(newUrl) == 2 and len(url) == 2:
				newUrl[1] = "%s&%s" % (url[1], newUrl[1])
			self.path = "?".join(newUrl)
			print "Rewrite from %s to %s" % (orginalURL, self.path)

			if len(rewriteRule) == 3 and rewriteRule[2].find("L"):
				break
		
		# Search for CGI executable
		if self.path.find("?") != -1:
			workPath = self.path[0:self.path.find("?")]
		else:
			workPath = self.path
		for extension in self.extensions:
			if workPath[-len(extension):].lower() == extension.lower():
				self.cgiExecutable = self.extensions[extension]
				return True
		return False

	def run_cgi(self):
		try:
			# Set CGI environment variables
			env = {
				"GATEWAY_INTERFACE": "CGI/1.1",
				"SERVER_NAME": "Simple HTTP Server",
				"SERVER_SOFTWARE": "Simple HTTP Server",
				"SERVER_PROTOCOL": self.protocol_version,
				"REQUEST_METHOD": self.command,
				"PATH_INFO": self.path,
				"QUERY_STRING": self.path[self.path.find("?") + 1:],
				"REQUEST_URI": self.orginalPath,
				"REMOTE_ADDR": self.client_address[0]
			}
			if self.path.find("?") != -1:
				env["PATH_INFO"] = self.path[0:self.path.find("?")]
			else:
				env["QUERY_STRING"] = ""
			env["SCRIPT_NAME"] = env["PATH_INFO"]
			env["PATH_TRANSLATED"] = "./" + env["PATH_INFO"]
			if self.headers.typeheader is None:
				env['CONTENT_TYPE'] = self.headers.type
			else:
				env['CONTENT_TYPE'] = self.headers.typeheader
			length = self.headers.getheader('content-length')
			if length:
				env['CONTENT_LENGTH'] = length
			for header in self.headers:
				env['HTTP_' + header.upper()] = self.headers[header]
			os.environ.update(env)

			# Execute CGI
			prog = os.popen2(self.cgiExecutable + " " + env["PATH_TRANSLATED"], 'b')
			if self.command.lower() == "post" and int(length) > 0:
				prog[0].write(self.rfile.read(int(length)))
			prog[0].close()
			firstLine = prog[1].readline()
			if firstLine[0:6] == "Status":
				self.wfile.write(self.protocol_version + firstLine[7:-1] + "\r\n") 
			elif firstLine[0:3] != "HTTP":
				self.wfile.write(self.protocol_version + " 200 Ok\r\n")
			self.wfile.write(firstLine)
			shutil.copyfileobj(prog[1], self.wfile)
		except:
			self.wfile.write("HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n\r\nCGI Error")

if __name__ == "__main__":
	"Use default port 13000 or port given in cmd"
	if len(sys.argv) == 1:
		port = 13000
	else:
		port = int(sys.argv[1])

	"Change into the htdocs directory"
	os.chdir(htdocs)

	"Signal handler for save exit"
	def onSignal(sign, stack):
		sys.exit(0)
	signal.signal(signal.SIGINT, onSignal)

	"Load htaccess"
	if os.access(".htaccess", os.R_OK):
		print "Using htaccess"
		htaccessFile = open(".htaccess", "r").read()
		if re.search("RewriteEngine On", htaccessFile, re.IGNORECASE):
			rewriteRules = re.findall("^RewriteRule ([^ ]+) ([^ ]+)(?: (.*))?$", htaccessFile, re.MULTILINE)
		else:
			rewriteRules = []
	else:
		rewriteRules = []
			
	"Save settings"
	RequestHandler.rewriteRules = rewriteRules
	RequestHandler.extensions = extensions
	
	"Start httpd"
	httpd = BaseHTTPServer.HTTPServer(('', port), RequestHandler)
	httpd.serve_forever()
