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)