# HG changeset patch # User paulb # Date 1115059972 0 # Node ID 81b6b0717b317051dccc5808d8001dcb2b3eba54 # Parent bc563090df091cc920cbf4b2123df6ac521f487c [project @ 2005-05-02 18:52:52 by paulb] Changed the behaviour of MapResource so that a mapping for None defines the "catch all" resource when nothing else matches the request path. Added a static directory publishing resource in Static. diff -r bc563090df09 -r 81b6b0717b31 WebStack/Resources/ResourceMap.py --- a/WebStack/Resources/ResourceMap.py Fri Jun 20 22:30:13 2008 +0200 +++ b/WebStack/Resources/ResourceMap.py Mon May 02 18:52:52 2005 +0000 @@ -14,7 +14,8 @@ Initialise the resource with a 'mapping' of names to resources. The 'mapping' should be a dictionary-like object employing simple names without "/" characters; the special value None is used where no name - is found in the request path. + corresponds to that used in the request path and may be used to map to + a "catch all" resource. """ self.mapping = mapping @@ -30,24 +31,28 @@ parts = trans.get_virtual_path_info().split("/") - # The first part should always be empty. + # The first part should always be empty, and there should always be a + # second part. - if len(parts) > 1: - name = parts[1] - else: - name = None + name = parts[1] # Get the mapped resource. resource = self.mapping.get(name) + if resource is None: + resource = self.mapping.get(None) - # If a resource was found, change the transaction's path info, then - # invoke the transaction, transferring control completely. + # If a resource was found, change the transaction's path info. + # eg. "/this/next" -> "/next" + # eg. "/this/" -> "/" + # eg. "/this" -> "/" new_path = parts[0:1] + (parts[2:] or [""]) new_path_info = "/".join(new_path) trans.set_virtual_path_info(new_path_info) + # Invoke the transaction, transferring control completely. + if resource is not None: resource.respond(trans) return diff -r bc563090df09 -r 81b6b0717b31 WebStack/Resources/Static.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebStack/Resources/Static.py Mon May 02 18:52:52 2005 +0000 @@ -0,0 +1,78 @@ +#!/usr/bin/env python + +""" +Resources for serving static content. +""" + +from WebStack.Generic import ContentType, EndOfResponse +import os + +class DirectoryResource: + + "A resource serving the contents of a filesystem directory." + + def __init__(self, directory, media_types=None, unrecognised_media_type="application/data"): + + """ + Initialise the resource to serve files from the given 'directory'. + + The optional 'media_types' dictionary can be used to map filename + extensions to media types, where extensions consist of the part of a + name after a "." character (such as "txt", "html"), and where media + types are the usual content descriptions (such as "text/plain" and + "text/html"). + + If 'media_types' contains a mapping from None to a media type, then + this mapping is used when no extension is present on a requested + resource name. + + Where no media type can be found for a resource, a predefined media + type is set which can be overridden by specifying a value for the + optional 'unrecognised_media_type' parameter. + """ + + self.directory = directory + self.media_types = media_types or {} + self.unrecognised_media_type = unrecognised_media_type + + def respond(self, trans): + + "Respond to the given transaction, 'trans', by serving a file." + + parts = trans.get_virtual_path_info().split("/") + filename = parts[1] + out = trans.get_response_stream() + + # Test for the file's existence. + + pathname = os.path.join(self.directory, filename) + if not (os.path.exists(pathname) and os.path.isfile(pathname)): + trans.set_response_code(404) + trans.set_content_type(ContentType("text/plain")) + out.write("Resource '%s' not found." % filename) + raise EndOfResponse + + # Get the extension. + + extension_parts = filename.split(".") + + if len(extension_parts) > 1: + extension = extension_parts[-1] + media_type = self.media_types.get(extension) + else: + media_type = self.media_types.get(None) + + # Set the content type. + + if media_type is not None: + trans.set_content_type(ContentType(media_type)) + else: + trans.set_content_type(ContentType(self.unrecognised_media_type)) + + # Write the file to the client. + + f = open(os.path.join(self.directory, filename), "rb") + out.write(f.read()) + f.close() + +# vim: tabstop=4 expandtab shiftwidth=4