'Handle a request, using PATH_INFO and QUERY_STRING from environ.
There are six required query string parameters: width, height,
xmin, ymin, xmax and ymax. Layer name must be supplied in PATH_INFO.'

def __call__(self, environ, start_response):

    try:
        for var in 'QUERY_STRING    PATH_INFO'.split():
            if (var not in environ):
                raise KnownUnknown(('Missing    "%s"    environment    variable' % var))
        query = dict(parse_qsl(environ['QUERY_STRING']))
        for param in 'width    height    xmin    ymin    xmax    ymax'.split():
            if (param not in query):
                raise KnownUnknown(('Missing    "%s"    parameter' % param))
        layer = environ['PATH_INFO'].strip('/')
        layer = self.config.layers[layer]
        provider = layer.provider
        if (not hasattr(provider, 'renderArea')):
            raise KnownUnknown(('Layer    "%s"    provider    %s    has    no    renderArea()    method' % (layer.name(), provider.__class__)))
        (width, height) = [int(query[p]) for p in 'width    height'.split()]
        (xmin, ymin, xmax, ymax) = [float(query[p]) for p in 'xmin    ymin    xmax    ymax'.split()]
        output = StringIO()
        image = provider.renderArea(width, height, None, xmin, ymin, xmax, ymax, None)
        image.save(output, format='PNG')
        headers = [('Content-Type', 'image/png')]
        if layer.allowed_origin:
            headers.append(('Access-Control-Allow-Origin', layer.allowed_origin))
        if (layer.max_cache_age is not None):
            expires = (datetime.utcnow() + timedelta(seconds=layer.max_cache_age))
            headers.append(('Expires', expires.strftime('%a    %d    %b    %Y    %H:%M:%S    GMT')))
            headers.append(('Cache-Control', ('public,    max-age=%d' % layer.max_cache_age)))
        start_response('200    OK', headers)
        return output.getvalue()
    except KnownUnknown as e:
        start_response('400    Bad    Request', [('Content-Type', 'text/plain')])
        return str(e)
