0001from httpencode.registry import get_format, find_format_match, find_format_accept
0003from paste.httpheaders import ACCEPT
0004from paste.response import header_value
0005
0006class InsecureFormatError(Exception):
0007 """
0008 Raised when for some reason an insecure format is used in a
0009 non-trusted situation.
0010 """
0011
0012def parse_request(environ, output_type=None, trusted=False,
0013 format=None):
0014 """
0015 Parses a WSGI request, attempting to get the given output type.
0016
0017 If ``trusted`` is true, then insecure formats will be allowed.
0018 """
0019 if format is None and output_type is None:
0020 raise TypeError(
0021 "You must give either an output_type or format argument")
0022 if format is None:
0023 format = find_format_match(output_type,
0024 get_mimetype_from_environ(environ, True))
0025 if output_type is not None:
0026 assert format.type == output_type, (
0027 "Type of format %r (%r) does not match given type %r"
0028 % (format, format.type, output_type))
0029 output_type = format.type
0030 return format.parse_request(environ, trusted=trusted)
0031
0032def parse_response(response, output_type, trusted=False, format=None):
0033 """
0034 Parses an HTTPResponse, attempting to get the given output type.
0035
0036 If ``trusted`` is true, then insecure formats will be allowed.
0037 """
0038 if format is None and output_type is None:
0039 raise TypeError(
0040 "You must give either an output_type or format argument")
0041 if format is None:
0042 format = find_format_match(output_type,
0043 get_mimetype_from_response(response, True))
0044 if output_type is not None:
0045 assert format.type == output_type, (
0046 "Type of format %r (%r) does not match given type %r"
0047 % (format, format.type, output_type))
0048 return format.parse_response(response, trusted=trusted)
0049
0050def get_mimetype_from_environ(environ, strip_params=False):
0051 """
0052 Get the mimetype from the WSGI environ
0053 """
0054 mimetype = environ.get('CONTENT_TYPE')
0055 if not mimetype:
0056 raise ValueError(
0057 "No CONTENT_TYPE in request environ")
0058 if strip_params:
0059 return mimetype.split(';', 1)[0]
0060 else:
0061 return mimetype
0062
0063def get_mimetype_from_response(response, strip_params=False):
0064 """
0065 Get the mimetype from the HTTP response
0066 """
0067 mimetype = response.getheader('Content-type', None)
0068 if not mimetype:
0069 raise ValueError(
0070 'No Content-Type header in response')
0071 if strip_params:
0072 return mimetype.split(';', 1)[0]
0073 else:
0074 return mimetype
0075
0076def get_mimetype_from_headers(headers, strip_params=False):
0077 mimetype = header_value(headers, 'Content-type')
0078 if not mimetype:
0079 raise ValueError(
0080 'No Content-Type header in headers: %r' % headers)
0081 if strip_params:
0082 return mimetype.split(';', 1)[0]
0083 else:
0084 return mimetype
0085
0086class Responder(object):
0087
0088 """
0089 WSGI application that serves a specific piece of data. The data should
0090 not be mutated after creating this application.
0091
0092 You must either pass in the type of the data (a string) or a format
0093 object that you want to use. You can provide a default_format for use when
0094 the client doesn't pass in an Accept header.
0095 """
0096
0097 def __init__(self, data, type=None, format=None, headers=None,
0098 content_type=None, default_format=None):
0099 if type is None and format is None:
0100 raise TypeError(
0101 "You must provide a type or format argument")
0102 if type is not None and format is not None:
0103 assert format.type == type, (
0104 "type argument (%r) and format (%r; type=%r) do not match"
0105 % (type, format, format.type))
0106 self.data = data
0107 self.type = type
0108 if isinstance(format, basestring):
0109 format = get_format(format)
0110 self.format = format
0111 if isinstance(default_format, basestring):
0112 default_format = get_format(default_format)
0113 self.default_format = default_format
0114 self.headers = headers
0115 self.content_type = content_type
0116
0117 def __call__(self, environ, start_response):
0118 content_type = None
0119 if self.format is None:
0120 accept = ACCEPT.parse(environ)
0121 if not accept:
0122 if self.default_format:
0123 format = self.default_format
0124 else:
0125 raise ValueError(
0126 'No Accept header provided in a request, and no format or '
0127 'default_format given')
0128 else:
0129 format, content_type = find_format_accept(self.type, accept)
0130 else:
0131 format = self.format
0132 app = format.responder(self.data, content_type=content_type)
0133 return app(environ, start_response)