def process_response(self, request, response):
    startedDateTime = request.META.get('MASHAPE_ANALYTICS.STARTED_DATETIME', datetime.utcnow())

    requestHeaders = [{'name': re.sub('^HTTP_', '', header), 'value': value} for (header, value) in request.META.items() if header.startswith('HTTP_')]
    requestHeaderSize = self.request_header_size(request)
    requestQueryString = [{'name': name, 'value': (value[0] if len(value) > 0 else None)} for name, value in parse_qs(request.META.get('QUERY_STRING', '')).items()]

    r = request.META.get('galileo.request')
    requestContentSize = r.content_length or 0

    responseHeaders = [{'name': header, 'value': value[-1]} for (header, value) in response._headers.items()]
    responseHeadersSize = self.response_header_size(response)
    responseContentSize = len(response.content)

    alf = Alf(self.serviceToken, self.environment, self.client_address(request))
    alf.addEntry({
      'startedDateTime': startedDateTime.isoformat() + 'Z',
      'serverIpAddress': socket.gethostbyname(socket.gethostname()),
      'time': int(round((datetime.utcnow() - startedDateTime).total_seconds() * 1000)),
      'request': {
        'method': request.method,
        'url': request.build_absolute_uri(),
        'httpVersion': 'HTTP/1.1',
        'cookies': [],
        'queryString': requestQueryString,
        'headers': requestHeaders,
        'headersSize': requestHeaderSize,
        'content': {
          'size': requestContentSize,
          'mimeType': request.META.get('CONTENT_TYPE', 'application/octet-stream')
        },
        'bodySize': requestHeaderSize + requestContentSize
      },
      'response': {
        'status': response.status_code,
        'statusText': response.reason_phrase,
        'httpVersion': 'HTTP/1.1',
        'cookies': [],
        'headers': responseHeaders,
        'headersSize': responseHeadersSize,
        'content': {
          'size': responseContentSize,
          'mimeType': response._headers.get('content-type', (None, 'application/octet-stream'))[-1]
        },
        'bodySize': responseHeadersSize + responseContentSize,
        'redirectURL': response._headers.get('location', ('location', ''))[-1]
      },
      'cache': {},
      'timings': {
        'blocked': -1,
        'dns': -1,
        'connect': -1,
        'send': 0,
        'wait': int(round((datetime.utcnow() - startedDateTime).total_seconds() * 1000)),
        'receive': 0,
        'ssl': -1
      }
    })

    # import json
    # print json.dumps(alf.json, indent=2)

    Capture.record(alf.json)

    return response
  def __call__(self, env, start_response):
    env['MashapeAnalytics.startedDateTime'] = datetime.utcnow()
    env['MashapeAnalytics.responseContentSize'] = 0

    # Capture response body from iterable
    iterable = None
    try:
      for data in self.app(env, self.wrap_start_response(env, start_response)):
        yield self.count_response_content_size(env, data)
    finally:
      if hasattr(iterable, 'close'):
        iterable.close()

      # Construct and send ALF
      r = Request(env)

      requestHeaders = [{'name': self.request_header_name(header), 'value': value} for (header, value) in env.items() if header.startswith('HTTP_')]
      requestHeaderSize = self.request_header_size(env)
      requestQueryString = [{'name': name, 'value': value[0]} for name, value in parse_qs(env.get('QUERY_STRING', '')).items()]

      requestContentSize = r.content_length

      responseHeaders = [{'name': header, 'value': value} for (header, value) in env['MashapeAnalytics.responseHeaders']]
      responseHeadersSize = self.response_header_size(env)

      alf = Alf(self.serviceToken, self.environment, self.client_address(env))
      entry = {
        'startedDateTime': env['MashapeAnalytics.startedDateTime'].isoformat() + 'Z', # HACK for MashapeAnalytics server to validate date
        'serverIPAddress': socket.gethostbyname(socket.gethostname()),
        'time': int(round((datetime.utcnow() - env['MashapeAnalytics.startedDateTime']).total_seconds() * 1000)),
        'request': {
          'method': env['REQUEST_METHOD'],
          'url': self.absolute_uri(env),
          'httpVersion': env['SERVER_PROTOCOL'],
          'cookies': [],
          'queryString': requestQueryString,
          'headers': requestHeaders,
          'headersSize': requestHeaderSize,
          'bodySize': requestHeaderSize + requestContentSize
        },
        'response': {
          'status': env['MashapeAnalytics.responseStatusCode'],
          'statusText': env['MashapeAnalytics.responseReasonPhrase'],
          'httpVersion': 'HTTP/1.1',
          'cookies': [],
          'headers': responseHeaders,
          'headersSize': responseHeadersSize,
          'content': {
            'size': env['MashapeAnalytics.responseContentSize'],
            'mimeType': [header for header in env['MashapeAnalytics.responseHeaders'] if header[0] == 'Content-Type'][0][1] or 'application/octet-stream'
          },
          'bodySize': responseHeadersSize + env['MashapeAnalytics.responseContentSize'],
          'redirectURL': next((value for (header, value) in env['MashapeAnalytics.responseHeaders'] if header == 'Location'), '')
        },
        'cache': {},
        'timings': {
          'blocked': -1,
          'dns': -1,
          'connect': -1,
          'send': 0,
          'wait': int(round((datetime.utcnow() - env['MashapeAnalytics.startedDateTime']).total_seconds() * 1000)),
          'receive': 0,
          'ssl': -1
        }
      }
      if env['CONTENT_LENGTH'] != '0':
        entry['request']['content'] = {
          'size': requestContentSize,
          'mimeType': env['CONTENT_TYPE'] or 'application/octet-stream'
        }
      alf.addEntry(entry)

      # import json
      # print json.dumps(alf.json, indent=2)

      Capture.record(alf.json)