# HG changeset patch # User paulb # Date 1125079908 0 # Node ID d10d59ba3f963f3ac3c8b674844d12c8a5cce3f8 # Parent 63cf9982f1b4991083ef42cf33890e8251602001 [project @ 2005-08-26 18:11:48 by paulb] Moved ContentType and HeaderValue to WebStack.Helpers.Request, along with the parse_header_value implementation. Added a parse_headers function. Added FileContent objects to hold uploaded file content and metadata. diff -r 63cf9982f1b4 -r d10d59ba3f96 WebStack/Helpers/Request.py --- a/WebStack/Helpers/Request.py Fri Aug 26 18:10:52 2005 +0000 +++ b/WebStack/Helpers/Request.py Fri Aug 26 18:11:48 2005 +0000 @@ -87,6 +87,71 @@ self.stream.close() +class HeaderValue: + + "A container for header information." + + def __init__(self, principal_value, **attributes): + + """ + Initialise the container with the given 'principal_value' and optional + keyword attributes representing the key=value pairs which accompany the + 'principal_value'. + """ + + self.principal_value = principal_value + self.attributes = attributes + + def __getattr__(self, name): + if self.attributes.has_key(name): + return self.attributes[name] + else: + raise AttributeError, name + + def __str__(self): + + """ + Format the header value object, producing a string suitable for the + response header field. + """ + + l = [] + if self.principal_value: + l.append(self.principal_value) + for name, value in self.attributes.items(): + l.append("; ") + l.append("%s=%s" % (name, value)) + + # Make sure that only ASCII is used. + + return "".join(l).encode("US-ASCII") + +class ContentType(HeaderValue): + + "A container for content type information." + + def __init__(self, media_type, charset=None, **attributes): + + """ + Initialise the container with the given 'media_type', an optional + 'charset', and optional keyword attributes representing the key=value + pairs which qualify content types. + """ + + if charset is not None: + attributes["charset"] = charset + HeaderValue.__init__(self, media_type, **attributes) + + def __getattr__(self, name): + if name == "media_type": + return self.principal_value + elif name == "charset": + return self.attributes.get("charset") + elif self.attributes.has_key(name): + return self.attributes[name] + else: + raise AttributeError, name + class Cookie: """ @@ -98,6 +163,66 @@ self.name = name self.value = value +class FileContent: + + """ + A simple class representing uploaded file content. This is useful in holding + metadata as well as being an indicator of such content in environments such + as Jython where it is not trivial to differentiate between plain strings and + Unicode in a fashion also applicable to CPython. + """ + + def __init__(self, content, headers=None): + + """ + Initialise the object with 'content' and optional 'headers' describing + the content. + """ + + self.content = content + self.headers = headers or {} + + def __str__(self): + return self.content + +def parse_header_value(header_class, header_value_str): + + """ + Create an object of the given 'header_class' by determining the details + of the given 'header_value_str' - a string containing the value of a + particular header. + """ + + if header_value_str is None: + return header_class(None) + + l = header_value_str.split(";") + attributes = {} + + # Find the attributes. + + principal_value, attributes_str = l[0].strip(), l[1:] + + for attribute_str in attributes_str: + t = attribute_str.split("=") + if len(t) > 1: + name, value = t[0].strip(), t[1].strip() + attributes[name] = value + + return header_class(principal_value, **attributes) + +def parse_headers(headers): + + """ + Parse the given 'headers' dictionary (containing names mapped to values), + returing a dictionary mapping names to HeaderValue objects. + """ + + new_headers = {} + for name, value in headers.items(): + new_headers[name] = parse_header_value(HeaderValue, value) + return new_headers + def get_storage_items(storage_body): """ @@ -146,9 +271,9 @@ # Detect stray FileUpload objects (eg. with Zope). if hasattr(field_value, "read"): - return field_value.read() + return FileContent(field_value.read(), parse_headers(field_value.headers)) else: - return field_value.value + return FileContent(field_value.value, parse_headers(field_value.headers)) else: return get_body_field(field_value, encoding)