1 #!/usr/bin/env python 2 3 """ 4 Resources for serving static content. 5 """ 6 7 from WebStack.Generic import ContentType, EndOfResponse 8 import os 9 10 class DirectoryResource: 11 12 "A resource serving the contents of a filesystem directory." 13 14 def __init__(self, directory, media_types=None, unrecognised_media_type="application/data"): 15 16 """ 17 Initialise the resource to serve files from the given 'directory'. 18 19 The optional 'media_types' dictionary can be used to map filename 20 extensions to media types, where extensions consist of the part of a 21 name after a "." character (such as "txt", "html"), and where media 22 types are the usual content descriptions (such as "text/plain" and 23 "text/html"). 24 25 If 'media_types' contains a mapping from None to a media type, then 26 this mapping is used when no extension is present on a requested 27 resource name. 28 29 Where no media type can be found for a resource, a predefined media 30 type is set which can be overridden by specifying a value for the 31 optional 'unrecognised_media_type' parameter. 32 """ 33 34 self.directory = directory 35 self.media_types = media_types or {} 36 self.unrecognised_media_type = unrecognised_media_type 37 38 def respond(self, trans): 39 40 "Respond to the given transaction, 'trans', by serving a file." 41 42 parts = trans.get_virtual_path_info().split("/") 43 filename = parts[1] 44 out = trans.get_response_stream() 45 46 # Test for the file's existence. 47 48 pathname = os.path.join(self.directory, filename) 49 if not (os.path.exists(pathname) and os.path.isfile(pathname)): 50 trans.set_response_code(404) 51 trans.set_content_type(ContentType("text/plain")) 52 out.write("Resource '%s' not found." % filename) 53 raise EndOfResponse 54 55 # Get the extension. 56 57 extension_parts = filename.split(".") 58 59 if len(extension_parts) > 1: 60 extension = extension_parts[-1] 61 media_type = self.media_types.get(extension) 62 else: 63 media_type = self.media_types.get(None) 64 65 # Set the content type. 66 67 if media_type is not None: 68 trans.set_content_type(ContentType(media_type)) 69 else: 70 trans.set_content_type(ContentType(self.unrecognised_media_type)) 71 72 # Write the file to the client. 73 74 f = open(os.path.join(self.directory, filename), "rb") 75 out.write(f.read()) 76 f.close() 77 78 # vim: tabstop=4 expandtab shiftwidth=4