CSC309: Web ProgrammingGreg Wilson 1 ! We have seen:What HTTP requests and responses look likeHow to write a CGI program that a web server can invoke to create dynamic contentThis lecture looks at (some of) what happens in betweenOnly way to really understand how web servers work is to build oneA good way to introduce internationalization, security, and other topics" #$# We could write code to:Manage socketsParse incoming HTTP requestsEtc.Python library provides a class to do thisBaseHTTPServer.HTTPServer creates a port, then listens to it for requestsYou must derive a class of your own from BaseHTTPRequestHandler to handle requests Handle GET in do_GET(), POST in do_POST(), etc.%& '(from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServerclass RequestHandler(BaseHTTPRequestHandler):def handleRequest(self):page = self.createPage()self.sendPage(page)do_GET = handleRequestdo_POST = handleRequest…rest of class…if __name__ == '__main__':serverAddress = ('', 80)server = HTTPServer(serverAddress, RequestHandler)server.serve_forever()CSC309: Web ProgrammingGreg Wilson 2) & Page = '''\<html><body><h1>Nitinat/Python V1.0 Page</h1><table cellpadding="3" border="1"><tr> <td>Date and time</td> <td>%(dateTime)s</td> </tr><tr> <td>Client host</td> <td>%(clientHost)s</td> </tr><tr> <td>Client port</td> <td>%(clientPort)s</td> </tr><tr> <td>Command</td> <td>%(command)s</td> </tr><tr> <td>Path</td> <td>%(path)s</td> </tr></body></html>'''*) & def createPage(self):values = {'dateTime' : self.date_time_string(),'clientHost‘ : self.client_address[0],'clientPort‘ : self.client_address[1],'command' : self.command,'path' : self.path}return self.Page % valuesdef sendPage(self, page):self.send_response(200)self.send_header("Content-type", "text/html")self.send_header("Content-Length", str(len(page)))self.end_headers()self.wfile.write(page)+ , Next step: give users filesRequire path to file to be part of URL Interpret path as relative to what?If path identifies a directory, return a listingError handlingTypical 20% or more of real applications But often ignored in programming coursesDefine our own exception class, and an error handling method-& if __name__ == '__main__':# Set the handler's root directory.if len(sys.argv) < 2:print >> sys.stderr, "Usage: Nitinat.py _base_directory_"sys.exit(1)root = os.path.abspath(sys.argv[1])if not os.path.isdir(root):print >> sys.stderr, "No such directory '%s'" % rootsys.exit(1)RequestHandler.RootDirectory = root# Create and run server.serverAddress = ('', 80)server = HTTPServer(serverAddress, RequestHandler)server.serve_forever()CSC309: Web ProgrammingGreg Wilson 3.) & class RequestHandler(BaseHTTPRequestHandler):RootDirectory = None # must be set externally before running# Classify and handle request.def handleRequest(self):# Handle any errors that aren't handled elsewhere.try:# Class not yet initialized.if self.RootDirectory is None:raise ServerException, "Root directory not set"# Figure out what exactly is being requested.fullPath = self.createAbsolutePath()) & # It doesn't exist...if not os.path.exists(fullPath):raise ServerException, "'%s' not found" % self.path# ...it's a file...elif os.path.isfile(fullPath):self.handleFile(fullPath)# ...it's a directory...elif os.path.isdir(fullPath):self.handleDir(fullPath)# ...we can't tell.else:raise ServerException, "Unknown object '%s'" % self.path) & # Handle errors.except Exception, msg:self.handleError(msg)# Handle GET and POST the same way.do_GET = handleRequestdo_POST = handleRequest# Handle unknown objects.def handleError(self, msg):content = self.ErrorPage % {'path' : self.path, 'msg' : msg}self.sendContent(content)) & # Create the absolute path for a request.def createAbsolutePath(self):head = os.path.abspath(self.RootDirectory)result = os.path.normpath(os.path.join(head, self.path))return result# Handle files.def handleFile(self, fullPath):try:input = file(fullPath, "r")content = input.read()input.close()self.sendContent(content)except IOError, msg:msg = "'%s' cannot be read: %s" % (self.path, msg)self.handleError(msg)CSC309: Web ProgrammingGreg Wilson 4") & # Handle directories.def handleDir(self, fullPath):try:listing = os.listdir(fullPath)filler = '\n'.join([(self.ListingItem % item) for item in listing])content = self.ListingPage % {'path' : self.path, 'filler' : filler}self.sendContent(content)except IOError, msg:msg = "'%s' cannot be listed: %s" % (self.path, msg)self.handleError(msg)%/ ')HTTP defines how to report errors403: No Permission404: Not Found500: Internal ErrorModify server to do the right thingAnd add loggingCreate a record of what the server didSlows things down slightly……but makes administrators’ (and programmers’) lives much, much better& "class RequestHandler(BaseHTTPRequestHandler):Debug = FalseERR_NO_PERM = 403ERR_NOT_FOUND = 404ERR_INTERNAL = 500def handleRequest(self):self.log("path is '%s'" % self.path)try:# Class not yet initialized.if self.RootDirectory is None:self.errInternal("Root directory not set")return*) & "# Figure out what exactly is being requested.absPath = self.createAbsolutePath()self.log("absPath is '%s'" % absPath)# It isn't below the root path.if not self.isParentDirectory(self.RootDirectory, absPath):self.log("absPath not below root directory")msg = "Path '%s' not below root directory '%s'" % \(absPath, self.RootDirectory)self.errNoPerm(msg)# It doesn't exist.elif not os.path.exists(absPath):self.log("absPath doesn't exist")self.errNotFound(absPath)CSC309: Web ProgrammingGreg Wilson 5+) & "elif os.path.isfile(absPath):self.log("absPath is a
View Full Document