from __future__ import absolute_import, division, print_function
from webob import Request, Response
from .visitor import Visitor
from .util import nonce, transparent_pixel, pixel_tag, Signer, SignerError
[docs]class ManhattanMiddleware(object):
def __init__(self, app, log, secret, cookie_name='manhattan',
pixel_path='/vpixel.gif', host_map=None, buffer_writes=True):
self.app = app
self.cookie_name = cookie_name
self.log = log
self.signer = Signer(secret)
self.pixel_path = pixel_path
self.host_map = host_map or {}
self.buffer_writes = buffer_writes
[docs] def inject_pixel(self, resp):
tag = pixel_tag(self.pixel_path)
def wrap_iter(orig_iter):
for chunk in orig_iter:
yield chunk.replace('</body>', '%s</body>' % tag)
resp.app_iter = wrap_iter(resp.app_iter)
[docs] def handle_pixel(self, visitor, fresh):
if not fresh:
visitor.pixel()
resp = Response(transparent_pixel)
resp.content_type = 'image/gif'
return resp
[docs] def count_page(self, req):
return (req.method in ('GET', 'POST') and
req.headers.get('X-Purpose') != 'preview')
[docs] def get_visitor_id(self, req):
signed_value = req.cookies[self.cookie_name]
return self.signer.unsign(signed_value)
def __call__(self, environ, start_response):
req = Request(environ)
fresh = vid = None
if self.cookie_name in req.cookies:
try:
vid = self.get_visitor_id(req)
except SignerError:
pass
else:
fresh = False
if not vid:
vid = nonce()
fresh = True
site_id = self.host_map.get(req.host.split(':', 1)[0], 0)
req.environ['manhattan.visitor'] = visitor = Visitor(
vid, self.log, site_id, self.buffer_writes)
if self.pixel_path and req.path_info == self.pixel_path:
resp = self.handle_pixel(visitor, fresh)
else:
resp = req.get_response(self.app)
if self.count_page(req):
visitor.page(req)
if fresh:
resp.set_cookie(self.cookie_name, self.signer.sign(visitor.id),
httponly=True)
if self.pixel_path and resp.content_type == 'text/html':
self.inject_pixel(resp)
visitor.flush()
return resp(environ, start_response)