Пример #1
0
    def __call__(self, environ, start_response):
        """Method that is called by the running WSGI server.

        You should NOT be calling this method yourself under normal circumstances.
        """
        response_headers = {}
        response_status = 0
        iterable = None
        req = Request(environ)

        def _start_response(_status, _response_headers, *args):
            write = start_response(_status, _response_headers, *args)

            # Populate response info (headers & status)
            nonlocal response_headers, response_status

            response_headers = _response_headers
            response_status = _status

            return write

        try:
            req.rm_start_dt = str(datetime.datetime.now())
            req.rm_start_ts = int(time.time() * 1000)

            if req.method == "POST":
                # The next 4 lines are a workaround for a serious shortcoming in the
                # WSGI spec.
                #
                # The data can only be read once, after which the socket is exhausted
                # and cannot be read again. As such, we read the data and then
                # repopulate the variable so that it can be used by other code down the
                # pipeline.
                #
                # For more info: https://stackoverflow.com/a/13106009/643951

                # the environment variable CONTENT_LENGTH may be empty or missing
                try:
                    content_length = int(environ.get("CONTENT_LENGTH", 0))
                except (ValueError):
                    content_length = 0
                content_body = environ["wsgi.input"].read(content_length)

                # guarding check to close stream
                if hasattr(environ["CONTENT_LENGTH"], "close"):
                    environ["wsgi.input"].close()

                environ["wsgi.input"] = io.BytesIO(content_body)

                req.rm_content_length = content_length
                req.rm_body = content_body

            iterable = self.app(environ, _start_response)
            for data in iterable:
                res_ctype = ""
                res_clength = 0

                htype = next(
                    (h for h in response_headers if h[0] == "Content-Type"),
                    None)

                hlength = next(
                    (h for h in response_headers if h[0] == "Content-Length"),
                    None)

                if htype and hlength:
                    res_ctype = htype[1]
                    res_clength = int(hlength[1])

                # Populate response body
                res = ResponseInfoWrapper(
                    response_headers,
                    response_status,
                    res_ctype,
                    res_clength,
                    data.decode("utf-8"),
                )

                # Send off data to be queued (and processed) by ReadMe if allowed
                if self.config.ALLOWED_HTTP_HOSTS:
                    if environ["HTTP_HOST"] in self.config.ALLOWED_HTTP_HOSTS:
                        self.metrics_core.process(req, res)
                else:
                    # If the allowed_http_hosts has not been set (None by default), send off the data to be queued
                    self.metrics_core.process(req, res)

                yield data

        finally:
            # Undocumented in WSGI spec but the iterable has to be closed
            if hasattr(iterable, "close"):
                iterable.close()