""" msHTTPHandler.py - class for handling HTTP requests (c) by Michael Stroeder This module is distributed under the terms of the GPL (GNU GENERAL PUBLIC LICENSE) Version 2 (see http://www.gnu.org/copyleft/gpl.html) $Id: msHTTPHandler.py,v 1.24 2007/03/09 17:16:23 michael Exp $ The HTTPHandlerClass is derived from class SimpleHTTPServer.SimpleHTTPRequestHandler. """ __version__ = '0.2.0' import sys,os,posixpath,stat,socket,string,time,SimpleHTTPServer,urllib,msbase,ipadr from time import strftime,gmtime def getExtensionMap(mime_types_pathname): """ Return dictionary with MIME types either read from file mime_types_pathname or a minimal default dictionay """ # MIME-mapping if mime_types_pathname and os.path.isfile(mime_types_pathname): # Read mapping from file print 'Read MIME-type mapping from file %s.' % (mime_types_pathname) import mimetypes extensions_map = mimetypes.read_mime_types(mime_types_pathname) extensions_map[''] = 'text/plain' # Default, *must* be present else: # Define very simple default mapping suitable for our needs extensions_map = { '': 'text/plain', # Default, *must* be present '.html': 'text/html', '.htm': 'text/html', '.gif': 'image/gif', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.css': 'text/css', } return extensions_map class HTTPHandlerClass(SimpleHTTPServer.SimpleHTTPRequestHandler): """ Sub-class for serving HTTP requests """ script_name = None # must be overloaded # server_env should be overloaded server_env = { 'SERVER_SOFTWARE':'msHTTPHandler %s' % __version__, 'DOCUMENT_ROOT':os.sep, } dir_listing_allowed = 0 access_allowed = map(ipadr.AddrMask_Str2Tuple,['127.0.0.1/255.0.0.0']) # Log file objects should be overloaded if running detached access_log = sys.stdout error_log = sys.stderr debug_log = sys.stdout extensions_map = getExtensionMap('') reverse_lookups = 0 # Make sure the connection is closed def finish(self): SimpleHTTPServer.SimpleHTTPRequestHandler.finish(self) self.connection.close() def translate_path(self,path): path = posixpath.normpath(urllib.unquote(path)) words = filter(None,path.split('/')) path = self.server_env['DOCUMENT_ROOT'] for word in words: path = os.path.join(path,word) return path def address_string(self): host, port = self.client_address if self.reverse_lookups: return socket.getfqdn(host) else: return host def log_error(self, format, *args): """Log error messages""" self.error_log.write("%s - - [%s] %s\n" % (self.address_string(), self.log_date_time_string(), format%args)) self.error_log.flush() def log_message(self, format, *args): """Log all access messages""" self.access_log.write("%s - - [%s] %s\n" % (self.address_string(), self.log_date_time_string(), format%args)) self.access_log.flush() def log_request(self, code='-', size='-'): """Log an accepted request.""" if code!=400: referer = self.headers.getheader('Referer','-') userAgent = self.headers.getheader('User-Agent','-') else: referer = '-';userAgent = '-' self.log_message('"%s" %s %s "%s" "%s"', self.requestline,str(code),str(size),referer,userAgent ) # Return usual CGI-BIN environment of current request as dictionary def get_http_env(self): directory, rest = '', self.path[1:] i = string.find(rest, '?') if i >= 0: rest, query = rest[:i], rest[i+1:] else: query = '' i = string.find(rest, '/') if i >= 0: script, rest = rest[:i], rest[i:] else: script, rest = rest, '' # env is the connection-dependent environment env = {} env.update(self.server_env) env['SERVER_NAME'] = self.server.server_name env['SERVER_PORT'] = str(self.server.server_port) env['CONTENT_TYPE'] = self.headers.typeheader or self.headers.type env['REQUEST_METHOD'] = self.command env['SCRIPT_NAME'] = self.script_name env['PATH_INFO'] = urllib.unquote(rest) env['QUERY_STRING'] = query env['REMOTE_ADDR'] = self.client_address[0] env['REMOTE_PORT'] = self.client_address[1] env['SCRIPT_FILENAME'] = sys.argv[0] env['REQUEST_URI'] = self.path[1:] for envitem in [ ('Content-length','CONTENT_LENGTH'), ('User-Agent','HTTP_USER_AGENT'), ('Accept','HTTP_ACCEPT'), ('Accept-Charset','HTTP_ACCEPT_CHARSET'), ('Accept-Encoding','HTTP_ACCEPT_ENCODING'), ('Accept-Language','HTTP_ACCEPT_LANGUAGE'), ('Referer','HTTP_REFERER'), ('Connection','HTTP_CONNECTION'), ]: http_header_value = self.headers.getheader(envitem[0]) if http_header_value: env[envitem[1]] = http_header_value # SERVER_SIGNATURE is built with string template and all connection data disp_env = msbase.DefaultDict('') disp_env.update(env) env['SERVER_SIGNATURE'] = self.server_env['SERVER_SIGNATURE'] % disp_env return env # Checks if remote IP address is allowed to access def check_IPAdress(self): return ipadr.MatchIPAdrList(self.client_address[0],self.access_allowed) # Send HTTP response 403 - access denied def Send403Error(self,http_env): disp_env = msbase.DefaultDict('') disp_env.update(http_env) self.send_response(403, "access denied") self.wfile.write("""Content-type: text/html 403 Access denied

Access denied

You are not allowed to access URL
%(REQUEST_URI)s
from IP address
%(REMOTE_ADDR)s.
%(SERVER_SIGNATURE)s """ % disp_env) def is_webapp(self): """Determine if the web application is accessed.""" if len(self.path)